C++の素敵

職場でC++における(dynamic_castではない)ダウンキャストは危ないよ、
って話があがっていたんだが、
これは普通に通ってしまうコードなので慣れてない人はやりがち。
みたいな話を思い出したので書いておく。

class B {
public:
    void hoge() {
        printf("Base::hoge\n");
    }
};

class D1 : public B {
public:
    D1() : value_(0) {
    }
    void hoge() {
        printf("D1::hoge\n");
    }
    short getValue() const {
        return value_;
    }
private:
    short value_;
};

class D2 : public B {
public:
    D2() : hoge_(666) {
    }
    void hoge() {
        printf("D2::hoge\n");
        hoge_ = 700000;
    }
private:
    int hoge_;
};

と、Bを継承したD1とD2がある。

で、

    B* b = new D1();
    D2* d2 = static_cast<D2*>(b);
    d2->hoge();

こんなコードが書ける。
コンパイルも通る。


さて、D1の筈のポインタをD2として実行したhogeに問題はないのだろうか?


これは勿論問題ありありで、
メモリ上では、
D2のhoge_とD1のvalue_は同じオフセットであるために、
D2がD2のつもりでhoge_を書き換えようとすると
実はD1である場合、value_が書き換わる。
しかも、value_はshortなので、
-20896
みたいな値に変わってしまう。


少なくともC++においてダウンキャストをする場合、
dynamic_castを使わないなら
「絶対」や「確実」でない限り、してはならない。


JavaならClassCastExceptionになってくれるんだけどね。

(あともしhogeがvirtual なメソッドだとD2のポインタとしてD1であるものを呼んでもD1のメソッドが呼ばれる)