読者です 読者をやめる 読者になる 読者になる

コンストラクタでの仮想関数呼び出し

  Hoge()
  {
    reinterpret_cast<HogeInher*>(this)->hoge();
    // とか
    HogeInher::hoge(); // こいつがstaticだとして
    // とか?
  }

こんなことやる人いんのかな・・・。

コンストラクタからの仮想関数呼び出しはNG - くそにそてくにっく

ありゃ、って思ったので。
そんな記法を使わなくても引き起こされる意図しない動作があります。

スーパークラスのコンストラクタにおいて、
仮想関数を呼び出したとき、
サブクラスのメンバ関数が呼ばれると
サブクラスはまだコンストラクトされていないので、
メンバ変数の値が不定であり、問題を引き起こすので
「コンストラクタでは仮想関数であっても
 自身のメンバ関数を呼び出しますよ」
ということです。

故に多くの場合期待する動作を行わないので
C++ではコンストラクタで仮想関数を使ってはいけない」
となります。
(仮想関数として動作すべきものがコンストラクタだけ意味を違える、というのは不自然)
勿論、このルールはコンストラクタ内部で呼び出された(仮想ではない)関数内でも適応されます。

class Hoge
{
public:
    Hoge() : bar_(0) {
        printf("Hoge::constructor\n");
        hoge();
    }
    virtual ~Hoge(){}
    virtual void hoge() {
        printf("Hoge::[%d]\n", bar_);
    }
private:
    int bar_;
};

class HogeInher : public Hoge
{
public:
    HogeInher() : foo_(0) {
        printf("HogeInher::constructor\n");
    }
    virtual void hoge() {
        // コンストラクタより前に呼び出されたらfoo_は不定だよ!
        printf("HogeInher::[%d]\n", foo_);
    }
private:
    int foo_;
};

int main()
{
    HogeInher hoge;
    // もしHogeInher::hogeが呼び出されたらfoo_は不定!
    return 0;
}
Hoge::constructor
Hoge::[0]
HogeInher::constructor