2 つの C++ クラスがあるとします。
class A
{
public:
A() { fn(); }
virtual void fn() { _n = 1; }
int getn() { return _n; }
protected:
int _n;
};
class B : public A
{
public:
B() : A() {}
virtual void fn() { _n = 2; }
};
次のコードを書いたとします。
int main()
{
B b;
int n = b.getn();
}
2 に設定されていると予想されるかもしれませんn
。
n
は1 に設定されていることがわかりました。なぜでしょうか?
ベストアンサー1
コンストラクターまたはデストラクタから仮想関数を呼び出すのは危険なので、可能な限り避けてください。すべての C++ 実装では、現在のコンストラクターの階層レベルで定義された関数のバージョンのみを呼び出す必要があります。
のC++ FAQ ライトこれについてはセクション 23.7 でかなり詳しく説明されています。フォローアップのために、そのセクション (および FAQ の残りの部分) を読むことをお勧めします。
抜粋:
[...] コンストラクターでは、派生クラスからのオーバーライドがまだ行われていないため、仮想呼び出しメカニズムは無効になっています。オブジェクトはベースから構築され、「派生前のベース」になります。
[...]
破棄は「派生クラスが基底クラスより先に」行われるため、仮想関数はコンストラクターの場合と同様に動作します。つまり、ローカル定義のみが使用され、オブジェクトの (破棄された) 派生クラス部分に触れないようにするためにオーバーライド関数は呼び出されません。
編集ほとんどすべてを修正しました (litb さん、ありがとう)