constメソッドについて




C++においてメンバ関数は、そのクラスのデータメンバを変更しないとき、constメンバ関数に指定できます。

list-1
    struct CHoge {
        int GetSurfaceType() const { return m_nSurfaceType; }
    private:
        int m_nSurfaceType;
    };


このconstは、そのメソッドを呼び出しても、データメンバは変更されないことを意味します。

しかし、(私が思うに)const性については二種類の考えかたがあります。

枠-1
1.データメンバを完全に変更しないことを意味する場合。(物理的const性)
2.データメンバを変更することはあるが、そのクラスの意義からして、それはconstだと言える場合。(論理的const性)


です。C++のコンパイラは、1.に従います。しかし、実際のC++プログラミングでは、2.に従うことが多いはずです。yaneSDK3rdも、2.の流儀に則しています。

たとえば、サーフェース(画面のこと⇒ISurface/CSurfaceInfoを参照のこと)を転送元から転送先へコピーする処理Bltについて考えてみましょう。

転送元は、参照のみなので、const性があると思われます。つまり、

枠-2
    void    Blt(ISurface* pDst , const ISurface* pSrc);


というように、転送元に関しては、constポインタで表現されるのが自然でしょう。ところが、転送元のピクセルを参照するためには、実際には、転送元サーフェースをlock〜unlockしないと、サーフェースのデータを参照できないかも知れません。ところが、lock〜unlockは、サーフェースの状態を変更するわけで、上記1.の定義から言えばconst性がありません。しかし、上記2.の定義ならば、読み出しのためにlock〜unlockが必要なので、lock〜unlockは、const性を保っていると考えるべきです。

yaneSDK3rdのISurfaceLockerという、サーフェースのlock〜unlockするオブジェクトの基底となるクラスがあるのですが、このクラスのlock/unlockメソッドがconstになっているのは、上記の2.の定義に従うからです。

ここで、constの規則を少しおさらいしておきましょう。さきほどの例のように

枠-3
    int GetSurfaceType() const { return m_nSurfaceType; }


constのついたクラスのメンバ関数(以下メソッドと呼ぶ)のことを、constメソッドと呼ぶことにします。

C++では、メソッドの呼び出しのときに、暗黙でthisを第1パラメータとして埋め込み呼び出します。このとき、constメソッドのなかでは、thisポインタの型は、

枠-4
    const CHoge* pThis;


のようになります。このconstメソッドの中から、同じクラスの非constメソッドを呼び出そうとしても、constポインタを非constポインタに暗黙でcastすることは出来ないので、呼び出すことは出来ません。

よって、この場合、const_castを用いて、次のように呼び出します。

list-2
    int ConstMethod() const {
        CHoge* pThis = const_cast<CHoge*>(this);
        //  const CHoge*から、CHoge*へキャストする
        return pThis->NotConstMethod();
    }


このconst_castは、やや強引ですが、論理的const性を考慮してクラス設計すると、メンバ変数を書き換えているメソッドをconst宣言しないといけないことが多々あるので、上記のようなテクニックを多用することになります。知っておかれると良いでしょう。