Notice : 内容無保証。禁無断転載。リンク不自由。

cast_sample.cpp

#include <iostream>

using std::cout ;
using std::endl ;

//

#define SHOW(p)    (p) ? (p)->show() : cout << "[NULL]" << endl

// アップキャスト/ダウンキャスト サンプル用クラス

class B {
public:
    virtual ~B(void){}
    virtual void show(void){cout << "[B]" << endl ;}
} ;

class D1 : public B {
public:
    virtual ~D1(void){}
    virtual void show(void){cout << "[D1]" << endl ;}
} ;

class D2 : public B {
public:
    virtual ~D2(void){}
    virtual void show(void){cout << "[D2]" << endl ;}
} ;

//
//
//

// アップキャスト

void upCastSample(void){
    B*  pB  = 0 ;
    D1* pD1 = 0 ;

    pD1 = new D1 ;

    pB = pD1 ;  // 基本クラスへの代入は暗黙のうちにキャストされる。
                // アップキャストは明示しないのが普通。

                                    // 明示しなければならないなら、
    // pB = (B*)pD1 ;             // と、旧来の Cスタイルのキャストも使えるが、
                                    // コンパイラの型チェックを黙らせてしまうので、
    // pB = static_cast<B*>(pD1) ;  // このように static_cast を用いるのが良い。

    SHOW(pB) ;

    delete pD1 ;
}

// ダウンキャスト

void downCastSample(void){
    B*  pB  = 0 ;
    D1* pD1 = 0 ;
    D2* pD2 = 0 ;

    pB = new D1 ;  // 暗黙のアップキャスト D1 → B

    // pD1 = pB ; // ダウンキャストするつもりでこう書いてもコンパイルエラーになる。ダウンキャストは明示しなければならない。

    // B → D1 のダウンキャスト (現在、pB は D1 のインスタンスを指しているので正当)
    pD1 = dynamic_cast<D1*>(pB) ;
    SHOW(pD1) ;

    // pD1 = pB ;                 // のコンパイルエラーを消すだけなら、
    // pD1 = (D1*)pB ;                // あるいは、
    // pD1 = static_cast<D1*>(pB) ; // でも良いが、以下の例のような不当なキャストの
                                    // チェックが出来ないため、危険なキャストである。

    // B → D2 のダウンキャスト (現在、pB は D2 のインスタンスを指していないので不当)
    pD2 = dynamic_cast<D2*>(pB) ;    // RTTI により互換性が無いことが検出され、0 が返る。
    SHOW(pD2) ;

    delete pB ;
}

//
//
//

// クロスキャスト サンプル用クラス

class B1 {
public:
    virtual ~B1(void){}
    virtual void show(void){cout << "[B1]" << endl ;}
} ;

class B2 {
public:
    virtual ~B2(void){}
    virtual void show(void){cout << "[B2]" << endl ;}
} ;

class D : public B1, public B2 {
public:
    virtual ~D(void){}
    virtual void show(void){cout << "[D]" << endl ;}
} ;

//
//
//

// クロスキャスト

void crossCastSample(void){
    B1* pB1 = 0 ;
    B2* pB2 = 0 ;
    D*  pD  = new D ;

    pB1 = pD ;  // 暗黙のアップキャスト

    // pB2 = pB1 ;    // クロスキャストするつもりでこう書いてもコンパイルエラーになる。クロスキャストは明示しなければならない。

    // B1 → B2 のクロスキャスト (現在 pB1 は B1、B2 両方の子クラス D のインスタンスを指しているので正当)
    pB2 = dynamic_cast<B2*>(pB1) ;
    SHOW(pB2) ;

    // pB2 = pB1 ;                        // のコンパイルエラーを消すために、
    // pB2 = static_cast<B2*>(pB1) ;    // と書くことは出来ない。
                                        // B1 と B2 は関連の無い型であるため、コンパイルエラーとなる。

    // pB2 = pB1 ;        // のコンパイルエラーを消すだけなら、旧来の Cスタイルのキャストを用い、
    // pB2 = (B2*)pB1 ;   // と書けるが、多重継承に対応できておらず、誤りである。

    if (dynamic_cast<B2*>(pB1) == (B2*)pB1) {
        cout <<
            "クロスキャストではポインタ値は変わらないので、\n" <<
            "Cスタイルのキャストで代用できる。"   <<
        endl ;
    }else{
        cout <<
            "クロスキャストするとポインタ値が変化するので、\n" <<
            "Cスタイルのキャストでは代用できない。" <<
        endl ;
    }

    // pD  = static_cast<D*>(pB1) ; // B1 → D のダウンキャスト
    // pB2 = static_cast<B2*>(pD) ; // D → B2 のアップキャスト

    // 旧来の Cスタイルのキャストでも 2回に分けて正しくキャストすればポインタ値は修正されるが、
    // 不当なキャストのチェックが出来ないため、使わないほうが良い。
    // pD  = (D*)pB1 ;        // B1 → D のダウンキャスト
    // pB2 = (B2*)pD ;        // D → B2 のアップキャスト
    //
    // pB2 = (B2*)(D*)pB1 ;   // 上の二行を一つにまとめて、こう書くこともできる。

    delete pD ;
}

main.cpp

void upCastSample(void) ;
void downCastSample(void) ;
void crossCastSample(void) ;

int main(void){
    upCastSample() ;
    downCastSample() ;
    crossCastSample() ;

    return 0 ;
}