学习记录:使用Qt在动态库之间实现信息传递
这是一篇学习记录关于如何在动态库之间进行数据传递。动态库在程序开发中的优势很明显可以极大提高开发效率降低模块之间耦合度但动态库之间实现数据交互也是常见需求。在Qt中实现动态库之间的数据交换有多种方式基于信号和槽机制是主要方式之一。信号和槽机制通常在类之间使用但在Qt的动态库之间仍然可以使用基于此机制的具体实现方案也同样有多种方式比如可以直接在主程序中包含动态库头文件在编译时连接动态库就可以直接进行库之间的信号传递这是Qt最常用的、也是最简单的一种动态库调用方法。也可以使用QLibrary加载动态库但任需要包含动态库头文件并在动态库中以C风格导出接口函数供主程序调用创建动态库对象。还有一种是利用Qt插件实现具体不再赘述。以上实现方式其实都没有离开Qt的信号和槽机制。不可否认信号和槽机制为程序开发提供了极大方便简化了程序开发但一个不可避免的限制就是主程序和动态库的开发不能离开Qt操作。如果对其它动态库有这样的需求实现这种方式仍然有其局限。因此要想这种需求实现能有更大范围的适应性还是得考虑C和C最初的实现机制。C和C没有信号和槽机制它的动态库之间的数据传递是通过回调函数实现的以下便是对回调函数实现的具体学习记录。在C中能够实现回调函数的基础是函数名同样是一个指针它也同样可以作为参数在函数之间进行传递。或许再解释一下对回调这个词的理解。回调字面意思像是回头调用实际上是在对象A中定义一个对象B对象A可以直接访问B中公有成员这是很自然的但是在B中并不能直接访问A这是不允许的逻辑上也不可实现因为A在B中是不可见的。但是我们不可避免会存在当B中的工作执行完成之后需要告知A这样的需求而实现这样需求的操作就是回调即在A创建了B在B中实现对A的调用。从上面对回调的解释可以发现在动态库之间实现信息传递与回调是一样的。我们在主程序中加载了动态库但要在动态库中向主程序传递信息好比主程序就是对象A动态库是对象B。如果没有回调一般情况下动态库是不可能访问主程序中的函数的那么动态库也就无法向主程序传递信息。我们前面已经说了上述需求可以通过回调来实现那么回调具体在动态库之间是如何操作的呢这里需要注意一点类和类之间同样存在回调只是具体实现操作相对简单一点而在动态库之间稍微麻烦一点。我们以一个简单的操作链路来描述这一操作过程它的核心思想就是传递函数指针。首先我们在动态库B中导出一个可供主程序A访问的函数函数名称就叫zhuce()其功能就是把A中的一个函数指针传递给动态库B然后在A中调用zhuce()函数将A中的一个函数比如caozuo()。它的函数名caozuo作为zhuce()的参数。zhuce()函数的具体实现代码是在动态库B中编写的其功能就是在A调用该函数时将传进来的参数caozuo函数的指针存下来所以在B中还需要定义一个函数类型指针变量fun_address用于存放caozuo的指针。在B获得函数caozuo的指针后也就代表A成功在B中注册了函数caozuo。那么在B中则可以通过fun_address这个存放函数指针的变量来执行函数caozuo的具体操作了。这也就实现了在B中调用A的函数的要求通过向fun_address代表函数caozuo传递参数也就实现了向A传递信息。以上详细阐述了回调实现的核心思想下面给出具体一个实现案例做进一步说明。首先建立一个共用的头文件用于声明一些主程序和动态库共用的定义这样做只是为了简化代码编写这些定义也可而在主程序和动态库编写时分别设置但需要保持形式一致。typedef void (*NotifyCallBackClose) (void *,int code, const QString msg);typedef QWidget* (*OpendllFunction)(QWidget *,QStringList);typedef void (*RegisterClosefunction)(NotifyCallBackClose,void *);extern NotifyCallBackClose outfunctionClose;//存放回调函数指针extern void * outObject;//在这个头文件中给出了5个定义NotifyCallBackClose表示回调函数的类型它的形式就是上文提到的caozuo()函数。NotifyCallBackClose类型是一个没有返回值但自带3个参数的函数3个参数分别是无类型指针、整型、字符串。NotifyCallBackClose类型的形式必须与caozuo()函数保持一致这个需要根据实际情况进行设计。OpendllFunction表示打开动态的函数类型这个函数类型与回调无关此处只是为了导出一个函数供主程序调用后创建动态库实例。它返回一个QWidget指针带QWidget 指针和QStringList两个类型参数。RegisterClosefunction表示注册函数类型它的形式就是上文中的zhuce()函数这是一个没有返回值带有2个参数的函数2个参数分别是NotifyCallBackClose类型和无类型指针。从这个函数类型就可以看出主程序注册函数时将NotifyCallBackClose类型的函数指针传递了出去同时传递了一个无类型指针。这里先说一下为什么要传递一个无类型指针它不是必须的但传递它的目的是为了便于对主程序中的类对象进行访问。也就是说这个无类型指针其实就是主程序的类对象地址。在上述头文件中还声明了两个全局变量这个含义就很简单outfunctionClose用于存放回调函数的地址outObject用于存放主程序的类对象地址。在此处不能对全局变量进行初始化否则在多个.cpp文件包含该头文件时会产生多个全局变量副本全局变量不唯一造成访问混乱。使用时只需在一个.cpp文件中进行初始化即可。动态库的头文件具体实现如下核心是声明两个导出函数供主程序调用。openOrbitSimulateWin函数与OpendllFunction类型保持一致主程序利用OpendllFunction来解析动态库中的openOrbitSimulateWin函数。registerCallBackClose与RegisterClosefunction类型一致主程序利用RegisterClosefunction来解析动态库中registerCallBackClose函数。#include “上述公共头文件”class ORBITSIMULATE_EXPORT OrbitSimulate: public QMainWindow{}extern C{ORBITSIMULATE_EXPORT OrbitSimulate * openOrbitSimulateWin(QWidget *p,QStringList args);ORBITSIMULATE_EXPORT void registerCallBackClose(NotifyCallBackClose cb,void * co);}动态库的.cpp文件实现如下。文件中首先对两个全局变量进行初始化然后是对两个导出函数的具体实现。openOrbitSimulateWin函数用于创建动态库实例并将实例对象返回给主程序。registerCallBackClose函数用于接收回调函数的地址和主程序对象的地址分别存放在两个全局变量中。最后在动态库类的析构函数中我们通过outfunctionClose指针调用来回调函数并将主程序对象指针和其它定义的参数传回去。outfunctionClose可以在类的任何成员函数中调用此处只是在动态库对象析构时告诉主程序一个信息。NotifyCallBackClose outfunctionClose nullptr;//存放回调函数指针void * outObject nullptr;//OrbitSimulate *openOrbitSimulateWin(QWidget *p, QStringList args){if(args.count() 0)//调用此库时必须传入至少一个数据库路径参数return new OrbitSimulate(p,args.at(0));//新建一个实例elsereturn nullptr;}void registerCallBackClose(NotifyCallBackClose cb,void * co){outfunctionClose cb;outObject co;}OrbitSimulate::~OrbitSimulate(){delete ui;if(outfunctionClose ! nullptr)//outfunctionClose只是回调函数的地址具体是在外部实现的outfunctionClose(outObject,0,OrbitSimulate);//}主程序相关实现代码如下。下面代码是动态库的解析和回调函数注册函数解析的几个必要条件一是知道动态库的路径用QLibrary 加载动态库二是知道需要解析的函数的名称和类型公用头文件中对动态库导出的函数类型进行了定义此处直接使用函数名称则必须要提前知道三是回调函数dealLibClose的形式必须与NotifyCallBackClose保持一致具体实现在主程序中。QLibrary * loadlib new QLibrary;loadlib-setFileName(“动态库路径”);OpendllFunction openlib (OpendllFunction)loadlib-resolve(“openOrbitSimulateWin”);QWidget * newWidget openlib(this,args);RegisterClosefunction registerCloseFun (RegisterClosefunction)loadlib-resolve(“registerCallBackClose”);registerCloseFun(dealLibClose,this);//注册函数供动态库调用可能存在的几个问题一、回调函数必须是静态的。在上述实现中被传递的回调函数必须是静态的可以是全局静态函数也可以是类成员静态函数。二、上述传递主程序对象指针的目的。我们知道静态函数不能访问主程序类中的普通成员。当需要在回调函数中执行一些复杂操作时将不可避免需要操作主程序对象。传递主程序对象指针的目的就是为了能够在回调函数中实现对主程序成员对象的访问。在回调函数中只需要将传递的无类型指针强制转换为主程序类的类型即可通过该指针访问成员对象。三、可能存在内存泄漏问题。在上述代码中如果主程序对象已经释放动态库再调用回调函数时这时传递的指针是非空的因为动态库传回的指针值是存放在动态库内部的全局变量中的动态库未释放时任然有值。回调函数将会得到一个非空指针而实际上这个指针指向的对象已经释放继续操作将导致非法访问程序直接崩溃。这就是上述代码存在的风险指针使程序更加灵活但也带来了风险。在这种情况下回调函数中是无法通过该指针来判断指针是否可用的。那么该如何来避免这种风险呢我们知道静态成员是在程序的main函数退出后最后释放的因此我们可以使用一个静态变量来标记一个对象是否被释放。在对象的析构函数中对该静态变量进行赋值在静态函数中通过该变量值来判断对象是否被释放从而避免非法访问风险。

相关新闻

VMware安装Windows 11全攻略:绕过TPM与性能优化

VMware安装Windows 11全攻略:绕过TPM与性能优化

1. 准备工作:环境与工具清单在VMware Workstation 16 Pro上安装Windows 11前,我们需要准备以下关键组件。这个环节往往被新手忽略,但实际决定了后续安装的成败。1.1 硬件需求核查主机CPU需支持虚拟化技术(Intel VT-x/AMD-V&#x…

2026/10/2 6:51:12 阅读更多 →
BiliTools终极指南:3步掌握免费跨平台B站视频下载工具

BiliTools终极指南:3步掌握免费跨平台B站视频下载工具

BiliTools终极指南:3步掌握免费跨平台B站视频下载工具 【免费下载链接】BiliTools 本项目已停止维护。 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools 你是否经常在B站(哔哩哔哩)上发现精彩的教学视频、心仪的番剧或…

2026/10/14 2:23:55 阅读更多 →
jemalloc与TLB shootdown性能问题分析与优化

jemalloc与TLB shootdown性能问题分析与优化

1. 问题背景:当jemalloc遇上TLB shootdown第一次在线上环境看到"TLB shootdown"这个监控指标突然飙升时,我和团队花了整整三天才定位到根源。那是一个典型的微服务架构,运行在Linux 5.4内核上,使用jemalloc 5.2.1作为默…

2026/10/13 4:07:06 阅读更多 →

最新新闻

linux-dash 全局 CSS 层解析:main、plugins-container、tables 如何撑起一套极简监控面板样式

linux-dash 全局 CSS 层解析:main、plugins-container、tables 如何撑起一套极简监控面板样式

运维观测指标监控监控大盘 【免费下载链接】linux-dash A beautiful web dashboard for Linux 项目地址: https://gitcode.com/gh_mirrors/li/linux-dash 点击查看 免费下载 本文以 src/css/README.md 中描述的"全局基础样式文件"(Global CSS…

2026/10/14 2:23:24 阅读更多 →
10.5 GHz 相控阵雷达开源了:四块板与 10 层混压 PCB 拆解

10.5 GHz 相控阵雷达开源了:四块板与 10 层混压 PCB 拆解

10.5 GHz 相控阵雷达开源了:四块板与 10 层混压 PCB 拆解 【免费下载链接】PLFM_RADAR Open-source, low-cost 10.5 GHz PLFM phased array RADAR system 项目地址: https://gitcode.com/GitHub_Trending/pl/PLFM_RADAR 如果告诉你,一套 16 通道 …

2026/10/14 2:23:24 阅读更多 →
Matlab findpeaks峰值检测:参数调优与实战避坑指南

Matlab findpeaks峰值检测:参数调优与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 2:23:24 阅读更多 →
Java小白如何三天速通redis?

Java小白如何三天速通redis?

大家都知道Redis的业务范围是非常广的,但是对于刚入行的小伙伴来说可能也就知道个缓存跟分布式锁。因为Redis的很多功能在一些小企业里,根本是用不到的,得等到并发量到了一定的程度,系统扛不住了,才会用到Redis那些高级…

2026/10/14 2:23:24 阅读更多 →
Viper 回连过滤(Handler Firewall):按 IP 精准管控监听回连的实战指南

Viper 回连过滤(Handler Firewall):按 IP 精准管控监听回连的实战指南

文档教程网络安全 【免费下载链接】Viper Adversary simulation and Red teaming platform with AI 项目地址: https://gitcode.com/gh_mirrors/vip/Viper 点击查看 免费下载 Viper 的**回连过滤(Handler Firewall)**是内置在监听器&#xf…

2026/10/14 2:23:24 阅读更多 →
A*算法在路径规划中的原理与实践优化

A*算法在路径规划中的原理与实践优化

1. 路径规划中的A*算法初探第一次接触A算法是在开发仓库机器人导航系统时。当时我们尝试了Dijkstra、深度优先搜索等各种路径规划方法,要么计算时间太长,要么找到的路径不够优化。直到一位同事推荐了A算法,测试效果令人惊艳——在100x100的网…

2026/10/14 2:22:24 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →