Qxt中的d-pointer技術及改進

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章