Qt 源码中有很多Q_Q和Q_D宏,使用这些宏的地方总会看到有q指针和d指针,查了查KDE文档,大体搞清了其中的机理,欧也!Qt的这些私有数据访问策略还是挺值得借鉴。下面就简单总结一下。

访问器 , `7 {$ C! D6 g( X
发了点牢骚,Qt的成员变量get访问器命名实在有点难以接受,get访问器和成员变量名一样,不像Bean的风格,有些编译器甚至通不过。命名的时候就还是加上get好点,习惯成自然,郁闷。 
5 q' i- z) F# s6 U( O0 Z
D-指针 ) D3 l6 Q: W; P# I0 E7 T* g$ W
私 有成员总是不可见的,Qt中私有成员不仅仅是简单封装一下,将访问权限改为private,它将所有私有数据封装在私有类里(命名就是 classname##private), 这样一来连用户都不知道他到底封装了什么,程序中只有这个私有类成员指针,这个指针就是D-指针。有1毛钱,以前都是把它藏在内衣兜里,现在不是啦,我把 它存在信用卡里,把信用卡藏在内衣兜里,够狠吧。。。   q( A( O+ N! p. M7 U  R" W
& _2 a/ T2 a& D$ y% Z- l! |/ ^6 J
假 如整个类的继承体系有点深怎么办,想用那一层的东西还要一点点的爬着去找,真麻烦! 没关系,有共享d指针呢,只需要在上一层里加个d指针就可以省去这么多麻烦了。它可以访问任意一层的私有数据(其实这样就不是private啦,叫 protected还差不多,有点不像OO),还可以获取父层的访问器。 
共享d指针实现方法如下: 
1、在基类中定义一个protected权限的d_ptr指针; 3 _2 k6 W5 v2 L1 }
2、在每个派生类中定义d_func(),获取基类d_ptr,并将其转换为当前私有类指针(派生自基类d_ptr); 6 @: r/ a/ {% q
3、在函数中使用Q_D,这样就可以使用d了; . G3 h) _! m9 C1 I7 V) e' t' t
4、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!!! " |0 F2 N% X7 j5 Z3 n
5、类的派生,加上protected 构造函数,调用父类构造函数,将私有数据类传参; 
3 N4 F  `& |1 ]3 A3 d
这里有个 共享d指针的例子。 ) U. n2 a. \% u2 G! q
基类: ' @, V+ z5 [7 @1 K& n& j5 H2 f
protected : 
  KFooBasePrivate * 
const d_ptr ; 7 ~4 H, H7 J9 x0 y# _8 R$ y9 a' z
  KFooBase ( KFooBasePrivate & dd , QObject * parent ); ) u( U9 ^% i2 H/ e1 m* w7 l
private : ' M$ y/ R9 K* U; W( K0 N1 y% s

friend 
class KFooBasePrivate ; $ f" \. `6 ]6 _$ c
. [: D3 Z( t* v: y1 S
inline KFooBasePrivate * d_func () 0 \% o* J2 d. [  O7 ]3 w: w! r

return d_ptr ; 
} % @% q& _- B% h  i* u

inline 
const KFooBasePrivate * d_func () 
const 

return d_ptr ; 3 H: ^1 w* I9 j. O2 _$ W
}

派生类: 3 X0 _. Y5 s% h
protected : 
  KFooDerived ( KFooDerivedPrivate & dd , QObject * parent ); 
private : 1 `9 }5 ~% g/ C

friend 9 x( A+ z0 D' k0 O* ?  S
class KFooDerivedPrivate ; 
( I1 \7 E, @6 l* P5 m
inline KFooDerivedPrivate * d_func () ' f$ C0 C5 `+ l2 g6 g+ q# F8 v* ]. o


return + }' H' o; k& P2 ~) ^/ @; L
reinterpret_cast < KFooDerivedPrivate *>( d_ptr ); 0 D" V" o1 c  A# H8 S+ Z
} $ p0 Q# ~6 W# i% u: V
, }/ Z; Q! K* M) S' {# K1 A) o) _: f
inline 
const KFooDerivedPrivate * d_func () 
const : }2 T7 Q% _3 i0 x
6 L' @9 `5 t# Q. N
{ * m0 @; Z3 `9 F6 }) {, D( }" k: c; \+ n. S
return 
reinterpret_cast < KFooDerivedPrivate *>( d_ptr ); 

. {  G8 V4 L! r5 d
前两步的声明工作交给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(); } 
/ w2 E) _  E9 P" V
// 在主类中的Private Data 声明,Q_D使用之 , Y5 t- I) l5 k2 W
#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)); } \ $ O6 v  t9 F0 c# a
    friend class Class##Private; 3 ]3 J5 q5 [2 A+ @) V7 k8 Z
, s# B3 C& N; Y- {3 V; }* S6 Q
// 在主类中的Private Data 声明(在d指针命名非d_ptr而是Dptr情况下使用),Q_D使用之 5 n4 Q. i$ B1 D# M
#define Q_DECLARE_PRIVATE_D(Dptr, Class) \ 1 R$ A! O8 A" T- \+ Z4 e
    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } \ + R+ g+ I5 M; m) `8 m
    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使用之 % D9 i" m: u7 [$ @
#define Q_DECLARE_PUBLIC(Class)                                    \   T$ c$ G3 M! I3 \8 X
    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()

/ T9 E. @! p: ~7 O+ V* B
感 觉Qt的这种机制破坏了OO,我想这就是它为何只做内部使用的原因吧。。。   有点完全依赖宏的味道,不像它的signal/slot,通过moc编译插入元数据。不过还是方便hack了。至于signal/slot,我想应该可 以通过macro和函数指针来作为替代方案,改天再see see。这里只是把看到的关于D指针的文章和自己的体会简单总结翻译一下,更详细的可以看下面两个连接。 2

http://www.cnblogs.com/SkylineSoft/articles/2046391.html

Q_D宏的更多相关文章

  1. Qt中的Q_D宏和d指针

    _ZTS7QObject 一.Q_D的在文件中的提法 Q_D的设置意在方便地获取私有类指针,文件为qglobal.h.下面的##是宏定义的连字符.假设类名是A,那么A##Private翻译过来就是AP ...

  2. d指针在Qt上的应用及实现(d指针能实现二进制兼容)

    Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念.那么为什么d指针能实现二进制兼容呢?为了回答这个问题,首先弄清楚什么是二进制兼容?所谓二进制兼容动态库,指的是一个在老版本库下运行的程序 ...

  3. QT源码分析(从QApplication开始)

    QT源码分析 转载自:http://no001.blog.51cto.com/1142339/282130 今天,在给同学讲东西的时候,谈到了Qt源代码的问题,才发现自己对Qt机制的了解是在太少了,而 ...

  4. d指针在Qt上的应用及实现

    Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念.那么为什么d指针能实现二进制兼容呢?为了回答这个问题,首先弄清楚什么是二进制兼容?所谓二进制兼容动态库,指的是一个在老版本库下运行的程序 ...

  5. 2、QT分析之QPushButton的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/ 在简单的QT程序的第二行,声明了一个QPushButto ...

  6. d指针在Qt上的应用及实现(有图,很清楚)

    Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念.那么为什么d指针能实现二进制兼容呢?为了回答这个问题,首先弄清楚什么是二进制兼容?所谓二进制兼容动态库,指的是一个在老版本库下运行的程序 ...

  7. QT分析之QPushButton的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/ 在简单的QT程序的第二行,声明了一个QPushButto ...

  8. 从pthread 到QThread

    该文出自:http://www.civilnet.cn/bbs/topicno/78430 使用线程技术进行应用编程的意义在gemfield的文章<从进程到线程>中已经介绍过了,我们就直奔 ...

  9. [转]QT中的D指针与Q指针

    Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念. 那么为什么d指针能实现二进制兼容呢? 为了回答这个问题,首先弄清楚什么是二进制兼容? 所谓二进制兼容动态库,指的是一个在老版本库下运行 ...

随机推荐

  1. boost signal2 trackable

    挺简单的一个类,只是维护了一个成员 shared_ptr<detail::trackable_pointee> _tracked_ptr; 这样看来的话,所谓的track还是基于智能指针, ...

  2. 使用fastcgi_cache加速网站

    为了提高网站的性能缓存是一把利器,nginx中可以配置fastcig_cache来缓存不需要实时获取的数据实现动静分离,nginx.conf配置如下: http {     -     fastcgi ...

  3. c 陷阱与缺陷(一)

    1.程序在设计时,往往得出正确的结果,但是它并不是程序员自己想要的. 例如: printf("hello world!") 编译器进行编译时不会出现任何问题,但是结果: 提示竟然出 ...

  4. flexbox弹性盒子模型

    这几天在做移动端的web开发,遇到了一些问题,之前没有折腾过这方面的东西,这次好好吸收下 css3的flexbox--弹性盒子模型,这个盒模型决定了一个盒子在其他盒子中的分布方式及如何处理可用的空间. ...

  5. TCP 监控工具 TCPMonitor

    1, membrane monitor Download: http://www.membrane-soa.org/downloads/archive/monitor-archive.htm 2, a ...

  6. php部分学习笔记

    [web 开发分为]1. 静态web 开发(html 页面) 如果我们的一个页面,始终是一成不变的,则就是属于静态web 开发,一般讲用html 技术就ok2. 动态web 开发 比如: 我们需要发帖 ...

  7. MongoDB 安装(一)

    windows 8安装 mongodb 1.下载安装包 http://www.veryhuo.com/down/html/mongodb.html 2.解压到D:/MongoDB目录下. 3.把D:/ ...

  8. 简单的实现树莓派的WEB控制

    最终效果如图: 用到的知识:Python Bottle HTML Javascript JQuery Bootstrap AJAX 当然还有 linux 我去,这么多--我还是一点一点说起吧-- 先贴 ...

  9. 哥德尔,图灵和康托尔 part 2 停机问题

    图灵著名的停机问题对于软件开发者而已是非常熟悉的.下面简单描述停机问题: 假设给你一个计算机程序的源代码,也给你所有程序要用的数据,文件,硬盘,DVD等等,所有它需要处理的东西.你能告诉我程序最终是否 ...

  10. select option 下拉多选单选bootstrap插件使用总结

    <select id="example-getting-started" multiple="multiple"> <option value ...