开发者网络

用户名  找回密码
 立即注册
帖子
热搜: 活动 交友 discuz
查看: 81|回复: 0

【大型软件开发】浅谈大型Qt软件开发(四)动态链接库的 ...

[复制链接]

1

主题

5

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2023-3-3 11:03:20 | 显示全部楼层 |阅读模式
由于知乎不支持MD语法,为了获得更好的阅读体验请移步本人博客【大型软件开发】浅谈大型Qt软件开发(四)动态链接库的宏冲突问题、COM组件开发的常见问题
最近工作的时候有一个链接库的对接工作,在对接时发生了一些小问题,这篇FAQ是办公室写这个库的工程师戴工写的,这里记录一下:

# 一、编译工程时报链接错误“不允许dllimport静态数据成员的定义”
## 1.错误截图

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210084921214-63076485.png)

## 2.错误原因分析

此错误是Q_OBJECT和Q_DECL_IMPORT宏共同作用时产生的结果。查询微软文档可知:静态数据成员无法在定义dllimport类的同一程序中指定定义。

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210084941347-2093452953.png)

这句话表明,导出类时,其静态成员不可被外部覆盖定义。举个例子,有导出类如下:

  ![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085004596-1817028464.png)

其中宏定义为:
![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085009631-1485003453.png)
根据微软关于dllimport的说明,类静态成员变量n不可被覆盖定义,即进行这样的操作
![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085026197-200174001.png)

可以看到,对普通成员函数fun进行覆盖,仅仅发出了编译警告,但编译器并没有明确拒绝这种行为,但在对静态成员n进行覆盖定义时,编译器报错,拒绝了此行为。

回过头来看Q_OBJECT宏的定义:

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085036104-303531264.png)

发现静态成员staticMetaObject,根据QMAKE规则,QT编译时会对包含有Q_OBJECT宏的类进行一次moc工作,而moc_*.cpp中刚好拥有staticMetaObject的定义操作:

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085051342-1733015183.png)

因此,Q_DECL_IMPORT(即dllimport)宏导出的类中包含了Q_OBJECT宏时,违反了编译器规则,因此无法完成编译。

## 3.修改策略

(1)修改导出类,如果导出类中含有Q_OBJECT宏,保留导出定义,去除导入定义;
(2)去除Q_DECL_IMPORT声明。由QT向导生成的宏声明文件中,有条件编译控制宏BUILD_STATIC,当工程中定义了该宏时,便可取消Q_DECL_IMPORT宏的导入声明;也可以不定义BUILD_STATIC宏,而是手动修改文件,去除Q_DECL_IMPORT宏。

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085230392-362254322.png)

(3)去除/注释Q_OBJECT宏。导入类时,可以在工程代码中将导入库头文件中的Q_OBJECT宏逐个注释。
![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085242663-1799490457.png)

(4)从工程中移除相关头文件。

![image](https://img2023.cnblogs.com/blog/3013923/202302/3013923-20230210085255915-867425916.png)

# 二、创建dll导入类时报警告“QObject: Cannot create children for a parent that is in a different thread.”

## 1. 错误截图


## 2.错误原因分析
这可能是由于工程编译版本类型与链接库的类型不一致导致,比如工程当前为debug版本,但链接库编译生成版本为release

## 3.错误修改策略

将工程生成版本调整为与链接库版本一致

# 三、单例写法:

原先的单例写法比较简单,代码大概如下:

        static Test&Test::Singleton(){
                static Test Instance;
                return Instance
        }
这样的单例模式看上去还行,这个也是我之前常用的单例模式。但是这个在COM组件的开发中是不够安全的,原因也很简单~因为我们提交给COM组件的IDispatch是指针形式提交的,这个指针有可能会在外部被析构掉(只是提出一种可能,这里尚未测试和验证),所以这个单例模式是指针不安全的。

既然如此我们就需要修改一种比较好用且指针安全的单例模式。今天看了下小余的代码我感觉还挺好用的,拿过来抄一下:

        static NetServer* NetServer::Singleton() {
                static QMutex mutext;
                static QSharedPointer<NetServer> inst;
                if (Q_UNLIKELY(!inst)) {
                        if (!inst) {
                                inst.reset(new NetServer());
                        }
                }
                return inst.data();
        }
这段代码就是用的QSharedPointer 智能指针对单例指针进行维护,这样只要主进程还在,这个单例的指针就会一直保存在QSharedPointer内,就不会被析构了,除非你自己提供了一个析构的方法。
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|开发者网络

GMT+8, 2025-5-9 19:03 , Processed in 0.584622 second(s), 69 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表