Qt之美(一):D指針/私有實現

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接:https://blog.csdn.net/zhu_xz/article/details/6035861
The English version is available at: http://xizhizhu.blogspot.com/2010/11/beauty-of-qt-1-d-pointer-private.htmlhtml

 

 

相信很多剛開始閱讀Qt源代碼的朋友在看到其中的Private類和諸如Q_D、Q_Q等宏時都會思考,爲何Qt要用這樣一個設計模式呢?這樣一段增長了很多複雜度的代碼,到底有多大的好處呢?簡單的說,這樣的好處在於保證代碼的二進制兼容性。設計模式

 

什麼是二進制兼容性?大名鼎鼎的KDE項目是這樣介紹的:一個庫是二進制兼容的,若是一個程序和某個庫的某個版本動態連接,而且不須要從新編譯,便可在安裝有該庫較新版本的環境中運行。爲何要保證二進制兼容性?若是不能保證庫的二進制兼容性,就意味着每次發佈新版本時,依賴該庫的全部程序都必須從新編譯才能正常運行。顯然,這對於像Qt這樣被普遍採用的庫而言是徹底不可接受的。關於二進制兼容性的更多信息,感興趣的朋友能夠參考下KDE TechBase上的這篇文章,這裏就不羅嗦了,僅僅和你們分享下具體的使用。函數

 

若是不使用D指針,那咱們可能會有以下的一個類聲明: this

class MyClass
{
public:
  MyClass();
  ~MyClass();
private:
  int myVar;
};

 

顯然,這裏的私有成員myVar是保證代碼二進制兼容性的大敵,因此咱們須要使用D指針,改寫這個類:spa

class MyClassPrivate;
class MyClass
{
public:
  MyClass();
  ~MyClass();
private:
  MyClassPrivate * const d_ptr;
  Q_DECLARE_PRIVATE(MyClass);
};

這裏,咱們定義了一個指針d_ptr指向私有實現類,而後用Q_DECLARE_PRIVATE宏來定義一些輔助函數和聲明友元類:.net

#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;

而後這個私有類的實現以下所示:設計

class MyClassPrivate
{
public:
  MyClassPrivate(MyClass *parent);
private:
  MyClass * const q_ptr;
  Q_DECLARE_PUBLIC(MyClass);
  int myVar;
};

這裏的q_ptr指針就是指向公開的接口了,而後Q_DECLARE_PUBLIC宏則定義了輔助函數並聲明瞭友元類:指針

#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;

而咱們還能夠用Q_D和Q_Q兩個宏來進一步簡化訪問:code

#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

這就是Qt中D指針/私有實現的最基本使用方法。最後用一個比較完整的例子做爲結尾;)htm

// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QtCore/QObject>
class MyClassPrivate;
class MyClass: public QObject
{
  Q_OBJECT
public:
  MyClass(QObject *parent = 0);
  virtual ~MyClass();
  void dummyFunc();
signal:
  void dummySignal();
private:
  MyClassPrivate * const d_ptr;
  Q_DECLARE_PRIVATE(MyClass);
  Q_DISABLE_COPY(MyClass);
};
#endif // MYCLASS_H
// myclass.cpp
#include "myclass.h"
class MyClassPrivate
{
public:
  MyClassPrivate(MyClass *parent)
    : q_ptr(parent)
  {
  }
  void foobar()
  {
    Q_Q(MyClass);
    emit q->dummySignal();
  }
private:
  MyClass * const q_ptr;
  Q_DECLARE_PUBLIC(MyClass);
};
MyClass::MyClass(QObject *parent)
  : QObject(parent)
  , d_ptr(new MyClassPrivate(this))
{
}
MyClass::~MyClass()
{
  Q_D(MyClass);
  delete d;
}
void MyClass::dummyFunc()
{
  Q_D(MyClass);
  d->foobar();
}
相關文章
相關標籤/搜索