Qt中宏定义的理解(持续更新)

QT_BEGIN_NAMESPACE 与 QT_END_NAMESPACE

以前Qt4是没有Qt命名空间的,后来才加上的,编译Qt源码时会有选项,是否将这些类放到专用的Qt命名空间内,默认是没有的。这就出来问题了,为了统一,如果你的代码在默认没有Qt命名空间的SDK中编译,那你就不用在前置声明下面这些类的时候加上命名空间,但如果你在有Qt命名空间的SDK中编译,那就得加上命名空间了,为了屏蔽这个差异,使得你的源码能在这两种情况下都进行编译,Qt提供了QT_BEGIN_NAMESPACE宏,这样开发者就省得自己来用程序或宏进行处理了。

QT_BEGIN_NAMESPACE
class QComboBox;
class QLabel;
class QToolButton;
QT_END_NAMESPACE

Q_INIT_RESOURCE 与 Q_CLEANUP_RESOURCE

项目中会使用某些资源文件比如 xxx.qrcQ_INIT_RESOURCE(xxx) 表示初始化该资源。
程序编译时,编译器根据传入的 xxx 将指定的 xxx.qrc 以二进制形式存储到 Qt 自动建立的名为 qrc_xxx.cpp 的文件中。
这个用法写在类的构造函数中,可确保在静态链接的情况下将资源链接到最终的应用程序二进制文件中;写在 main 函数中,则全局可以使用。

同理,需要将资源卸载时,可以使用 Q_CLEANUP_RESOURCE(xxx)

Q_DECL_EXPORT 与 Q_DECL_IMPORT

两个宏定义的源码如下:

#  ifdef Q_OS_WIN
#    define Q_DECL_EXPORT     __declspec(dllexport)
#    define Q_DECL_IMPORT     __declspec(dllimport)
#  elif defined(QT_VISIBILITY_AVAILABLE)
#    define Q_DECL_EXPORT     __attribute__((visibility("default")))
#    define Q_DECL_IMPORT     __attribute__((visibility("default")))
#    define Q_DECL_HIDDEN     __attribute__((visibility("hidden")))
#  endif

这两个宏定义在 Qt 助手中是释义如下:

Q_DECL_EXPORT must be added to the declarations of symbols used when compiling a shared library.
Q_DECL_IMPORT must be added to the declarations of symbols used when compiling a client that uses the shared library.

即:

  • Q_DECL_EXPORT 必须添加到编译共享库时使用的符号声明中
  • Q_DECL_IMPORT 必须添加到编译使用共享库的客户端时使用的符号声明。

在 Qt 创建共享库项目时,Qt 会自动生成一个 xxx_global.h 的文件,里面的代码类似如下:

#ifndef MYLIB_GLOBAL_H
#define MYLIB_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(MYLIB_LIBRARY)
#  define MYLIB_EXPORT Q_DECL_EXPORT
#else
#  define MYLIB_EXPORT Q_DECL_IMPORT
#endif

#endif // MYLIB_GLOBAL_H

同时,该共享库项目的 .pro 文件,也会默认生成一行代码:DEFINES += MYLIB_LIBRARY

由此可见,当编译该库时,宏定义 MYLIB_LIBRARYQ_DECL_EXPORT;而当库被其他程序链接使用时,由于没有其他程序没有原库项目 .pro 文件中的 DEFINES,因此 MYLIB_LIBRARYQ_DECL_IMPORT

当在共享库项目中新增自定义类时,新增类需要包含 xxx_global.h 的头文件,同时声明类时需要加上宏定义MYLIB_LIBRARY,示例如下:

#ifndef ANIMAL_H
#define ANIMAL_H

#include <QString>
#include "MyLib_global.h"

class MYLIB_EXPORT Animal
{
public:
    Animal();

private:
    QString m_type;
};

#endif // ANIMAL_H

如果不在 class 后加上宏定义 MYLIB_LIBRARY,当其他程序链接库对类进行实例化时,会报错“未定义对该类的引用”。

Q_DISABLE_COPY

源码如下:

/*
   Some classes do not permit copies to be made of an object. These
   classes contains a private copy constructor and assignment
   operator to disable copying (the compiler gives an error message).
*/
#define Q_DISABLE_COPY(Class) \
    Class(const Class &) Q_DECL_EQ_DELETE;\
    Class &operator=(const Class &) Q_DECL_EQ_DELETE;

所有继承自QObject的类都使用这个宏声明了他们的拷贝构造函数和赋值操作符为私有

试想如果我们有一个QPushButton对象btnSubmit,如果我们可以复制出一个和btnSubmint完全一样的button对象,那么新的button对象的名字应该是什么?如果也叫btnSubmit,当我们给其中的btnSubmit接收事件或发出信号时,系统如何区分把事件由哪个button对象接收,或者哪个对象发送了信号?

我们知道在各种容器中能以 value 方式存放的类型,必须有默认的构造函数,拷贝构造函数和赋值操作。由于 QObject 及所有继承自它的子类都没有提供拷贝构造和赋值操作,当我们使用 QList<QObject> 时,编译器就会报错。如果我们要在容器中存储这中类型的对象,我们就要使用它们的指针。如 QList<QObject *>

Q_DECLARE_PRIVATE 与 Q_DECLARE_PUBLIC

两个宏的源码如下:

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PUBLIC(Class)                                    \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

示例代码:

QtServiceController 
{
    Q_DECLARE_PRIVATE(QtServiceController) 
public:
    QtServiceController(const QString &name);
//省略其他 
private:
    QtServiceControllerPrivate *d_ptr; 
};

大概意思是如下:

  • QtServiceController 中通过 d_func() 可以获得 QtServiceControllerPrivate 的指针 d_ptr
  • QtServiceControllerPrivate 中通过 q_func() 可以获得 QtServiceController 的指针 q_ptr
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值