C++では不法!?
yoichiroさんの
さて,以下の抽象クラスがあったとする。これは,コンストラクタの中からfoo()メソッドを呼び出すが,foo()メソッドはサブクラスで実装を提供することを意味している。
Database Error
に臆面もなくC++でTB。
C++だとabstractはこう書けるのですが、
class C1 { public: C1() { foo(); }; virtual void foo() = 0; };
で、継承先、value=1の初期化はコンストラクタのところに。
class C2 : public C1 { private: int value; public: C2() : value(1) { printf("1:%d\n",value); } void foo() { printf("2:%d\n",value); value = 2; } };
ただこうすると
C++ではコンストラクタ内ではまだ適切なオブジェクトが構築されていないので、
オブジェクトのコンストラクタが完全に実行を終えるまでは、そのオブジェクトは建設中のビルのようなものである。未完成のビルには、さまざまな不便がつきものだ。はしごを使ったり、そのほか、危険に見合った対策を取らなければならない。
C++の設計と進化 - はてなキーワード
しかし建設が終わったら、コンパイラとユーザは、そのオブジェクトが使用可能だと想定できるのだ。
との通り、危険なので仮装関数はすべて自身の関数を呼び出します。
よって、C1のコンストラクタにおけるfooは純粋仮想関数であるC1::fooを呼び出そうとし、
g++はsymbolが見つからずコンパイルエラー。
bccは「Pure virtual function called」とランタイムエラーになってしまいます。
では、foo()を{printf("none\n");}としたらどうなるかというと、
none
1:1
となります。C1()->C1:foo()->C2()の順で呼び出し。
fooがinitializeとかsetup系の呼び出しであればえらいこっちゃですね。
また、fooでC2のものが呼ばれないのは
「C2のコンストラクタがまだ実行されていないのにC2:foo呼んで安全なのか?」
C1の人には(もしくは誰にも)わからないためです。(C++は初期化されてない値を触ったときの動作は未定義ですし)
C1()->C2:foo()->C2()って呼ばれたら恐ろしいですよね。
「インスタンスフィールドが勝手に初期化される!?」
と全然絡んでませんが参考までにとも。