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指针实现方法以下:
一、在基类中定义一个protected权限的d_ptr指针; 3 _2 k6 W5 v2 L1 }
二、在每一个派生类中定义d_func(),获取基类d_ptr,并将其转换为当前私有类指针(派生自基类d_ptr); 6 @: r/ a/ {% q
三、在函数中使用Q_D,这样就可使用d了; . G3 h) _! m9 C1 I7 V) e' t' t
四、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!!! " |0 F2 N% X7 j5 Z3 n
五、类的派生,加上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-指针