Qtソースプロファイル:情報非表示(2)


次は前編の基礎の上で、Qtのソースコードに入って、Qt 4を見てみましょう.xはPrivate Classesをどのように実現したのか.前に述べたように、Qのようなものがたくさん見られるかもしれません.DまたはQ_Qのようなマクロ.では、このようなコードを見てみましょう.
void MyClass::setFoo( int i )
{
	Q_D(MyClass);
	d->m_foo = i;
}

int MyClass::foo() const
{
	Q_D(const MyClass);
	return d->m_foo;
}

従来のC++のクラスでは、このようなgetterとsetterを実現するには、プライベート変数を使用する必要があります.i、そしてこの変数を操作します.前回のPrivate Classのやり方では、MyClassPrivateDataのようなクラスを構築し、ポインタを使用してすべてのデータ操作を依頼します.Qtの比較例を見てみましょう
class MyObject: public QObject
{
    Q_OBJECT

public:
    MyObject();
    virtual ~ MyObject();
    void setMemberX( int x );
    int memberX() const;
    void setMemberY( double y);
    double memberY() const;

signals:
    void priorityChanged( MyObject::Priority priority );

private:
    int        m_memberX;
    double m_memberY;

Qtの実現を見てみましょう.
 
class MyObjectPrivate;
class MyObject: public QObject
{
    Q_OBJECT

public:
    MyObject();
    virtual ~ MyObject();
    void setMemberX( int x );
    int memberX() const;
    void setMemberY( double y);
    double memberY() const;

signals:
    void priorityChanged( MyObject::Priority priority );

protected:
    MyObjectPrivate * const d_ptr;

private:
    Q_DECLARE_PRIVATE(MyObject);
};

この例は簡単で、一つは伝統的な方法で実現し、もう一つはQt 4を採用した.xの方法.Qt4.xの方法はD-Pointerと呼ばれています.dというポインタを使うからです.上に書いたd_のように.ptr.従来の方法ではprivateにすべてのプライベート変数を書く必要があります.通常、ファイル全体が長くなります.さらに重要なのは、ユーザーがこれらの情報を必要としないことです.D-Pointerを使用する方法では、私たちのインタフェースはとてもきれいになりました.長いプライベート変数は二度とありません.プライベート変数を一緒に公開する必要はありません.dポインタの中にあります.データ型などの情報を変更する場合は、ヘッダファイルを変更する必要はありません.プライベートデータクラスを変更するだけでいいです.注意しなければならないのは、単純なC++クラスとは異なり、プライベートクラスがsignalsとslotsを定義する必要がある場合は、前の記事のようにcppファイルに置くのではなく、この定義をヘッダファイルに置くべきです.これはqmakeが検出するだけだからです.hファイルのQ_OBJECTマクロ.もちろん、このようなprivate classをクラスの同じヘッダファイルに置くべきではありません.そうすると意味がありません.一般的な方法は、myclass_p.hを使用した名前付けなどのprivateのヘッダファイルを定義することです.(これもQtのネーミング方法です).privateヘッダファイルをパブリッシュしたincludeの下に置かないでください.これはパブリッシュの一部ではありませんので、プライベートです.そして、myclassヘッダファイルで、
 
class MyClassPrivate;

このような前向きな声明は直接ではなく
 
#include "myclass_p.h"

この方式.これも、プライベートなヘッダファイルをパブリッシュしないようにするためであり、順方向宣言はコンパイル時間を短縮することができます.このクラスのprivateセクションでは、MyClassPrivateのconstポインタd_を使用します.ptr.このクラスのサブクラスにもこのポインタを使用させる必要がある場合は、このd_ptrはprotected部分に置かれ、上のコードのようになっています.さらにconstキーワードを追加して、一度だけ初期化できるようにしました.次に、私たちは不思議なマクロに出会った:Q_DECLARE_PRIVATE.これは何に使いますか.では、まずこのマクロの展開を見てみましょう.
 
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); } \
    inline const Class##Private* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); } \
    friend class Class##Private;

もしあなたがよく分からないなら、私たちのQを使ってください.DECLARE_PRIVATE(MyClass)展開を見てみましょう.
 
    inline MyClassPrivate* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); }
    inline const MyClassPrivate* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); }
    friend class MyClassPrivate;

実際に2つのinlineのd_を作成しましたfunc()関数、戻り値はそれぞれ私たちのd_です.ptrポインタとconstポインタ.また、MyClassPrivateクラスをMyClassのfriendとして宣言しています.これでMyClassというクラスでQ_を使うことができますD(MyClass)およびQ_D(const MyClass).私たちが最初に見たコードを覚えていますか?これを見てみましょうDはどこが神聖なのか!
 
// A template function for getting the instance to your private class instance.
template  static inline T *qGetPtrHelper(T *ptr) { return ptr; }

// A macro for getting the d-pointer
#define Q_D(Class) Class##Private * const d = d_func()

 
次はやはり自分でこのマクロを広げて、
 
MyClassPrivate * const d = d_func()

 
簡単に言えばQtはd_からfunc()はMyClassPrivateポインタを取得するコードをカプセル化し,オブジェクト向けのgetter関数を用いてこのポインタを取得することができる.
 
QtがD-Pointerを使用して前述した情報隠蔽を実現する方法をよく知っています.しかし、もう一つの問題は、ほとんどのコードをMyClassPrivateに集中すると、MyClassPrivateの実装にMyClassのいくつかにアクセスさせる必要がある可能性が高いということです.今、私たちはメインクラスにD-Pointerを通じてMyClassPrivateのデータにアクセスさせますが、どのようにして逆にMyClassPrivateをメインクラスのデータにアクセスさせますか?Qtも対応するソリューションを提供しています.それはQ_です.Qマクロ、例えば:
 
class MyObjectPrivate
{
public:
    MyObjectPrivate(MyObject * parent):
            q_ptr( parent ),
            m_priority(MyObject::Low)
    {}
    void foo()
    {
        // Demonstrate how to make MyObject to emit a signal
        Q_Q(MyObject);
        emit q->priorityChanged( m_priority );
    }

    //  Members
    MyObject * const q_ptr;
    Q_DECLARE_PUBLIC(MyObject);
    MyObject::Priority m_priority;
};

 
privateクラスMyObjectPrivateでは、コンストラクション関数によってプライマリクラスMyObjectのポインタをq_に渡すptr.次に、プライマリクラスで使用されているようなQ_を使用します.DECLARE_PRIVATEのマクロのような別のマクロQ_DECLARE_PUBLIC.このマクロがやったのはQ_を通過させることですQ(Class)マクロは、主クラスポインタを使用します.D-Pointerとは異なり、このときに使う必要があるのはQ_ですPointer.この2つは完全に相対的であり,ここではこれ以上述べない.
 
これで,比較Qtを用いてPrivate Classesを用いて情報隠蔽を実現できるようになった.これはQtの実現だけでなく、もちろん、Q_を使わなくてもいいです.DとQ_Q、自分のやり方を使うのではなく、これらはどうでもいい.最も主要なのは,Qtのソースコードが教えてくれたC++クラスの設計構想を理解したことである.