[解決済み】コンストラクター内での仮想関数の呼び出し
2022-04-17 15:42:55
質問
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();
}
と予想されるかもしれません。
n
は2に設定されています。
ということが判明しました。
n
が1になっているのはなぜですか?
解決するには?
コンストラクタやデストラクタから仮想関数を呼び出すことは危険ですので、可能な限り避けるべきです。 すべての C++ 実装は、現在のコンストラクタの階層レベルで定義されたバージョンの関数を呼び出し、それ以上は呼び出さないようにします。
は C++ FAQ Lite は、23.7節でかなり詳細にこのことを扱っています。 フォローアップのために、それ(とFAQの残り)を読むことをお勧めします。
抜粋
<ブロッククオート[...] コンストラクタでは、派生クラスからのオーバーライドがまだ起こっていないため、仮想呼び出し機構は無効になっています。オブジェクトはベースから構築され、「派生クラスの前にベース」なのです。
[...]
破壊は「基底クラスの前に派生クラス」で行われるため、仮想関数はコンストラクタと同じように動作します。ローカル定義のみが使用され、オブジェクトの(現在破壊されている)派生クラス部分に触れないようにするため、オーバーライド関数は呼び出されません。
EDIT MostをAllに修正(litbさんありがとうございます)。
関連
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 仮想デストラクタはいつ使うのか?
-
[解決済み] C#でベースコンストラクタを呼び出す
-
[解決済み] 抽象メソッドと仮想メソッドの違いは何ですか?
-
[解決済み] C++で仮想関数が必要な理由とは?
-
[解決済み] コンストラクタ内の仮想メンバー呼び出し
-
[解決済み] template "と "typename "キーワードはどこに、なぜ入れなければならないのですか?
-
[解決済み】Pythonで複数のコンストラクタを持つためのクリーンでPythonicな方法は何ですか?
-
[解決済み】派生クラスでオーバーライドされた関数が、ベースクラスの他のオーバーロードを隠してしまうのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】'cout'は型名ではない
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み] 配列のベクトルを扱う正しい方法