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.qrc
,Q_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_LIBRARY
为 Q_DECL_EXPORT
;而当库被其他程序链接使用时,由于没有其他程序没有原库项目 .pro 文件中的 DEFINES
,因此 MYLIB_LIBRARY
为 Q_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
。