QT Q_D && Q_Q
http://cache.baidu.com/c?m=9d78d513d98007b8589cd7690c66c0616d4381136ac3975521dbc90ed5264c40347bfee17c3510738396273146b8492bbbad696f76447ce2c895c31781ee8f7871d572292b5ad11e0fd71df89f4672c3209b0be8ae4de1b9a637c3f983d38e5205dd537220c6afd5&p=8b2a921886cc47a911fcd520575d&user=baidu&fm=sc&query=qt+Q_D&qid=c7777d6b0063f6e9&p1=9
Qt 源码中有很多Q_Q和Q_D 宏,使用这些宏的地方总会看到有q指针和d指针,查了查KDE文档,大体搞清了其中的机理,欧也!Qt 的这些私有数据访问策略还是挺值得借鉴。下面就简单总结一下。
D-指针
私 有成员总是不可见的,Qt 中私有成员不仅仅是简单封装一下,将访问权限改为private,它将所有私有数据封装在私有类里(命名就是 classname##private), 这样一来连用户都不知道他到底封装了什么,程序中只有这个私有类成员指针,这个指针就是D-指针。有1毛钱,以前都是把它藏在内衣兜里,现在不是啦,我把 它存在信用卡里,把信用卡藏在内衣兜里,够狠吧。。。
假 如整个类的继承体系有点深怎么办,想用那一层的东西还要一点点的爬着去找,真麻烦! 没关系,有共享d指针呢,只需要在上一层里加个d指针就可以省去这么多麻烦了。它可以访问任意一层的私有数据(其实这样就不是private啦,叫 protected还差不多,有点不像OO),还可以获取父层的访问器。
共享d指针实现方法如下:
1、在基类中定义一个protected权限的d_ptr指针;
2、在每个派生类中定义d_func(),获取基类d_ptr,并将其转换为当前私有类指针(派生自基类d_ptr);
3、在函数中使用Q_D ,这样就可以使用d了;
4、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!!!
5、类的派生,加上protected 构造函数,调用父类构造函数,将私有数据类传参;
这里有个 共享d指针 的例子。
基类:
protected :
KFooBasePrivate * const d_ptr ;
KFooBase ( KFooBasePrivate & dd , QObject * parent );
private :
friend class KFooBasePrivate ;
inline KFooBasePrivate * d_func () { return d_ptr ; }
inline const KFooBasePrivate * d_func () const { return d_ptr ; }
派生类:
protected :
KFooDerived ( KFooDerivedPrivate & dd , QObject * parent );
private :
friend class KFooDerivedPrivate ;
inline KFooDerivedPrivate * d_func ()
{ return reinterpret_cast < KFooDerivedPrivate *>( d_ptr ); }
inline const KFooDerivedPrivate * d_func () const
{ return reinterpret_cast < KFooDerivedPrivate *>( d_ptr ); }
前两步的声明工作交给Q_DECLARE_PRIVATE宏去处理,就简单多了,我们所要做的就是在私有类的实现和Q_D 的使用。
template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }
// 在主类中的Private Data 声明,Q_D 使用之
#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;
// 在主类中的Private Data 声明(在d指针命名非d_ptr而是Dptr情况下使用),Q_D 使用之
#define Q_DECLARE_PRIVATE_D(Dptr, Class) /
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } /
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } /
friend class Class##Private;
#define Q_D (Class) Class##Private * const d = d_func()
Q-指针
搞清了d指针,q指针就简单多了,有没有发现’q’和’d’哪里有点像,是滴!’q’就是’d’倒过个来。q指针的方向正好和d指针相反,它是在私有数据类中使用的(d指针只在主类中使用,就是使用私有数据类的那个类,真拗口!),来获取主类指针。
// 在私有数据类中的Public Data声明,Q_Q使用之
#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_Q(Class) Class * const q = q_func()
感 觉Qt 的这种机制破坏了 OO,我想这就是它为何只做内部使用的原因吧。。。 有点完全依赖宏的味道,不像它的signal/slot,通过moc编译插入元数据。不过还是方便hack了。至于signal/slot,我想应该 可以通过macro和函数指针来作为替代方案,改天再see see。这里只是把看到的关于D指针的文章和自己的体会简单总结翻译一下,更详细的可以看下面两个连接。