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のメソッドが呼ばれる)