2013-04-10 5 views
9

は以下のQtのクラスを考えてみましょう:Qtはプライベートデータへのポインタをインスタンス化するためにd_func()を使用するのはなぜですか?

#include <QScopedPointer> 

class MyClassPrivate; 
class MyClass 
{ 
    public: 
     MyClass(); 
     ~MyClass(); 
    private: 
     QScopedPointer<MyClassPrivate> d_ptr; 
     Q_DECLARE_PRIVATE(MyClass) 
} 

このクラスは、プライベートな実装を実装するほとんどのQtのクラスの構造に似ています。マクロQ_DECLARE_PRIVATEは(Qt5のように)、以下の拡張が発生します。

inline MyClassPrivate* d_func() 
    { return reinterpret_cast<MyClassPrivate *>(qGetPtrHelper(d_ptr)); } 
inline const MyClassPrivate* d_func() const 
    { return reinterpret_cast<const MyClassPrivate *>(qGetPtrHelper(d_ptr)); } 
friend class MyClassPrivate; 

これは混乱して - なぜないd_ptrは、メンバ関数内で直接使用されていますか?言い換えれば、これを行う代わりに:

Q_D(MyClass); 
d->member = 12345; 

どうしたらいいですか?

d_ptr->member = 12345; 

(基本的に)ただd_ptrを返し、スタック上の余分な変数のオーバーヘッドが発生し、明示的な機能を持った理由は何ですか?

答えて

7

派生クラスと基本クラスがそれぞれプライベート構造を持っていると、メモリが無駄になり、Qtではプライベートクラスも継承され、派生クラスと基本クラスは1つのd_ptrを共有します。そうすることの問題は、d_ptrが現在BasePrivate型であることです。

class Base 
{ 
protected: 
    BasePrivate * d_ptr; 
} 

class Derived 
{ 
// There is not d_ptr declared 
} 

だからあなたはタイプが* BasePrivateで、それはd_ptrにアクセスしたときに、派生クラスでは、見ることができます。したがって、d_ptrをDerivedPrivate *にキャストする必要があります。 d_func関数はインラインであり、コンパイルされると常にd_ptrを正しい型にキャストします。

This postは、私がここで言うよりも優れています。あなたがそれを読むことをお勧めします。

+0

私のクラスが互いに継承していない場合、 'Q_DECLARE_PRIVATE'マクロを使用する利点はありますか?継承はインラインメソッドの唯一の理由ですか? –

+1

@ NathanOsmanお互いに継承していない2つのクラスを使用している場合は、マクロを使用する理由がないはずです。それぞれに個別の実装を持たせることができます。しかし、QtではほとんどすべてのクラスがQObjectクラスから継承されており、継承は非常に深刻な場合があります。そのようなメカニズムがなければ、メモリのオーバーヘッドが大きくなります。 –