Qxt是一個Qt的擴展庫。其中也用到了d-pointer技術,但是與Qt的區別很大,比起Qt有點不足之處。這裏我先簡單看下它的實現,然後吸取Qt中的優點進行改進。(最新代碼在 https://github.com/wang-bin/d-pointer )
之前寫過一篇關於d-pointer的文章 http://blog.csdn.net/ibingow/article/details/7522157 ,這裏很多細節就不重複了。
在qxtglobal.h中相關代碼
/****************************************************************************
** This file is derived from code bearing the following notice:
** The sole author of this file, Adam Higerd, has explicitly disclaimed all
** copyright interest and protection for the content within. This file has
** been placed in the public domain according to United States copyright
** statute and case law. In jurisdictions where this public domain dedication
** is not legally recognized, anyone who receives a copy of this file is
** permitted to use, modify, duplicate, and redistribute this file, in whole
** or in part, with no restrictions or conditions. In these jurisdictions,
** this file shall be copyright (C) 2006-2008 by Adam Higerd.
****************************************************************************/
#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
#define QXT_D(PUB) PUB##Private& d = qxt_d()
#define QXT_P(PUB) PUB& p = qxt_p()
template <typename PUB>
class QxtPrivate
{
public:
virtual ~QxtPrivate()
{}
inline void QXT_setPublic(PUB* pub)
{
qxt_p_ptr = pub;
}
protected:
inline PUB& qxt_p()
{
return *qxt_p_ptr;
}
inline const PUB& qxt_p() const
{
return *qxt_p_ptr;
}
inline PUB* qxt_ptr()
{
return qxt_p_ptr;
}
inline const PUB* qxt_ptr() const
{
return qxt_p_ptr;
}
private:
PUB* qxt_p_ptr;
};
template <typename PUB, typename PVT>
class QxtPrivateInterface
{
friend class QxtPrivate<PUB>;
public:
QxtPrivateInterface()
{
pvt = new PVT;
}
~QxtPrivateInterface()
{
delete pvt;
}
inline void setPublic(PUB* pub)
{
pvt->QXT_setPublic(pub);
}
inline PVT& operator()()
{
return *static_cast<PVT*>(pvt);
}
inline const PVT& operator()() const
{
return *static_cast<PVT*>(pvt);
}
inline PVT * operator->()
{
return static_cast<PVT*>(pvt);
}
inline const PVT * operator->() const
{
return static_cast<PVT*>(pvt);
}
private:
QxtPrivateInterface(const QxtPrivateInterface&) { }
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
QxtPrivate<PUB>* pvt;
};
具體不解釋了,不難理解。使用時在類定義里加上
QXT_DECLARE_PRIVATE(MyClass)
就會給你生成一個類似於智能指針的成員變量qxt_d,它只是一個藉口,真正存放數據的是MyClassPrivate這個類的指針pvt,繼承自 QxtPrivate<MyClass>,在qxt_d構造時產生。
私有類的寫法是
class MyClassPrivate : public QxtPrivate<MyClass>
{
....
}
一個缺點是派生類不能直接訪問基類的數據。可以在 Qxt的源碼中看到qxt_d都聲明爲 private的,而且每個類都有這個成員,並且都是相互獨立的,這個就顯得有點奇怪了。Qt的做法是數據成員都可以在派生類中訪問的,數據被聲明爲protected,並且Private類可以被繼承。
另外一個缺點就是構造一個類可能會分配很多次內存。一個類的第N代派生類構造時會new N次,因爲繼承鏈上的每個類都要給自己的private類分配內存。
我對qxt的代碼進行了修改,可以解決以上問題,並且使用也更簡單。形式上類似於Qt。不詳細解釋了
//QxtPrivateInterface<PUB, PUB##Private> qxt_d;
#define QXT_DECLARE_PRIVATE(PUB) \
inline PUB##Private& d_func() { return qxt_d.pri<PUB##Private>(); } \
inline const PUB##Private& d_func() const { return qxt_d.pri<PUB##Private>(); } \
friend class PUB##Private;
#define QXT_DECLARE_PUBLIC(PUB) \
inline PUB& q_func() { return *static_cast<PUB*>(qxt_ptr()); } \
inline const PUB& q_func() const { return *static_cast<PUB*>(qxt_ptr()); } \
friend class PUB;
#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
#define QXT_D(PUB) PUB##Private& d = qxt_d.pri<PUB##Private>()
#define QXT_P(Class) Class& p = *static_cast<Class*>(qxt_ptr())
//interface
template <typename PUB>
class QxtPrivate
{
public:
virtual ~QxtPrivate() {}
inline void QXT_setPublic(PUB* pub) { qxt_p_ptr = pub; }
protected:
inline PUB& qxt_p() { return *qxt_p_ptr; }
inline const PUB& qxt_p() const { return *qxt_p_ptr; }
inline PUB* qxt_ptr() { return qxt_p_ptr; }
inline const PUB* qxt_ptr() const { return qxt_p_ptr; }
private:
PUB* qxt_p_ptr;
};
//interface
template <typename PUB, typename PVT>
class QxtPrivateInterface
{
friend class QxtPrivate<PUB>;
public:
QxtPrivateInterface(PVT* d):pvt(d) {}
QxtPrivateInterface():pvt(new PVT) {}
~QxtPrivateInterface() {
if (pvt) {
delete pvt;
pvt = 0;
}
}
inline void setPublic(PUB* pub) { pvt->QXT_setPublic(pub); }
template <typename T>
inline T& pri() { return *reinterpret_cast<T*>(pvt); }
template <typename T>
inline const T& pri() const { return *reinterpret_cast<T*>(pvt); } //static cast requires defination of T
inline PVT& operator()() { return *static_cast<PVT*>(pvt); }
inline const PVT& operator()() const { return *static_cast<PVT*>(pvt); }
inline PVT * operator->() { return static_cast<PVT*>(pvt); }
inline const PVT * operator->() const { return static_cast<PVT*>(pvt); }
private:
QxtPrivateInterface(const QxtPrivateInterface&);
QxtPrivateInterface& operator=(const QxtPrivateInterface&);
QxtPrivate<PUB>* pvt;
};
使用如下:
對於祖先類Base,加上protected成員
class BasePrivate;
class Base
{
public:
Base();
protected:
Base(BasePrivate& d);
virtual ~Base();
QxtPrivateInterface<Base, BasePrivate> qxt_d;
};
如有需要也可以加上宏QXT_DECLARE_PRIVATE(Base),提供訪問私有類的簡便方法
然後定義BasePrivate,繼承自QxtPrivate<Base>
Base的派生類做法類似,只要再定義派生類相應的私有類
class DerivedPrivate : public BasePrivate
{
}
爲減小內存分配次數,派生類中調用基類的構造函數可以使用proteced裏的那個。
完
頭文件下載(包含如何使用):http://download.csdn.net/detail/ibingow/4765462