C++学习---qt的公有类、私有类、Q_Q、Q_D、二进制兼容
1、二进制兼容
如果程序从一个以前版本的库动态链接到新版本的库之后,能够继续正常运行,而不需要重新编译,那么我们就说这个库是二进制兼容的。
如果不能保证库的二进制兼容性,就意味着每次发布库的新版本时,依赖该库的所有程序都必须重新编译才能正常运行。
2、公有类、私有类
是解决信息隐藏的问题的,发布库文件时只提供公有类的头文件而不必提供私有类的头文件,从而隐藏掉一些不想公开的内容。
如果修改的内容是私有类里面的,那么重新编译库以后,对外的公有类并没有发生变化,从而达到二进制兼容的目的。
因此这样设计类的目的至少有两个:
(1)信息隐藏
(2)二进制兼容
你不应该把这样的 private class 放在你的类的同一个头文件中,因为这样做的话就没有意义了。常见做法是,定义一个 private 的头文件,例如使用 myclass_p.h 的命名方式(这也是 Qt 的命名方式)。并且记住,不要把 private 头文件放到你发布的 include 下面!因为这不是你发布的一部分,它们是私有的。
或者把私有类定义在公有类的cpp文件中。
一般是将公有类中的private成员放在私有类中。
3、Q_Q、Q_D
Q_Q是私有类访问公有类的方法。
Q_D是公有类访问私有类的方法。
template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; } template <typename Ptr> inline auto qGetPtrHelper(const Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); } #define Q_DECLARE_PRIVATE(Class) \ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \ friend class Class##Private; #define Q_DECLARE_PRIVATE_D(Dptr, Class) \ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr)); } \ inline const Class##Private* d_func() const { 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; #define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func()
以上设计也称为d-pointer,“d-pointer” 这个名字源于 Trolltech 公司的 Arnt Gulbrandsen,他首先将这项技术引入到 Qt 中,使其成为第一个在大版本之间保持二进制兼容性的 C ++ GUI 库之一。 所有看过它的人都很快将这种技术作为 KDE 库的一般编程模式。这是能够在不破坏二进制兼容性的情况下将新的私有数据成员添加到类中是一个很好的技巧。
一个简单的公有类、私有类设计例子为:
myclass.h
// myclass.h #ifndef MYCLASS_H #define MYCLASS_H #include <QtCore/QObject> class MyClassPrivate; class MyClass: public QObject { Q_OBJECT public: MyClass(QObject *parent = 0); virtual ~MyClass(); void dummyFunc(); signal: void dummySignal(); private: MyClassPrivate * const d_ptr; Q_DECLARE_PRIVATE(MyClass); Q_DISABLE_COPY(MyClass); }; #endif // MYCLASS_H
myclass.cpp
// myclass.cpp #include "myclass.h" class MyClassPrivate { public: MyClassPrivate(MyClass *parent) : q_ptr(parent) { } void foobar() { Q_Q(MyClass); emit q->dummySignal(); } private: MyClass * const q_ptr; Q_DECLARE_PUBLIC(MyClass); }; MyClass::MyClass(QObject *parent) : QObject(parent) , d_ptr(new MyClassPrivate(this)) { } MyClass::~MyClass() { Q_D(MyClass); delete d; } void MyClass::dummyFunc() { Q_D(MyClass); d->foobar(); }