または、__declspec(novtable) を使用することによるその他の既知の悪影響はありますか? 問題への参照が見つからないようです。
2 に答える
MSCV はone vptr per object and one vtbl per class
、RTTI や仮想関数などの OO メカニズムを実装するために使用します。
そのため、vptr が正しく設定されている場合にのみ、RTTI と仮想機能は正常に動作します。
struct __declspec(novtable) B {
virtual void f() = 0;
};
struct D1 : B {
D1() {
} // after the construction of D1, vptr will be set to vtbl of D1.
};
D1 d1; // after d has been fully constructed, vptr is correct.
B& b = d1; // so virtual functions and RTTI will work.
b.f(); // calls D1::f();
assert( dynamic_cast<D1*>(&b) );
assert( typeid(b) == typeid(D1) );
を使用する場合、 B は抽象クラスである必要があります__declspec(novtable)
。
D1 のコンストラクタを除いて、B のインスタンスはありません。
また、ほとんどの場合、__declspec(novtable) に悪影響はありません。
しかし、派生クラスの構築中に、__declspec(novtable)
ISO C++ セマンティックとは異なるものになります。
struct D2 : B {
D2() { // when enter the constructor of D2 \
// the vtpr must be set to vptr of B \
// if B didn't use __declspec(novtable).
// virtual functions and RTTI will also work.
this->f(); // should calls B::f();
assert( typeid(*this) == typeid(B) );
assert( !dynamic_cast<D2*>(this) );
assert( dynamic_cast<B*>(this) );
// but __declspec(novtable) will stop the compiler \
// from generating code to initialize the vptr.
// so the code above will crash because of uninitialized vptr.
}
};
注: virtual f() = 0
; f を a にpure virtual function
、B を抽象クラスにします。純粋仮想関数( ではない)
のが欠落している可能性があります。
C++ では、コンストラクターでの仮想関数呼び出しが許可されていますが、これはお勧めできません。definition
could
must
更新: D2 の間違い: 派生コンストラクターの vptr。
struct D3 : B { // ISO C++ semantic
D3() { // vptr must be set to vtbl of B before enter
} // vptr must be set to vtbl of D2 after leave
};
ただし、 vptr は構築中は不定です。これが、コンストラクターでの仮想関数呼び出しが推奨されない理由の 1 つです。
D2::D2() の vptr が B で、B::f() の定義が欠落しているthis->f();
場合、vtbl で関数へのポインターを逆参照するとクラッシュします。
D2::D2() の vptr が B で、B が novtable を使用するthis->f();
場合、初期化されていない vptr を逆参照するとクラッシュします。
実際、D2::D2() の vptr は MSVC (msvc8) の D2 です。コンパイラは、D2::D2() で他のコードを実行する前に vptr を D2 に設定します。
D2 this->f();
::f() を呼び出すと、3 つのアサーションに違反します。
私が正しく理解している場合:ctorまたはdtor内の仮想fn呼び出しは、コンパイル時のリンクに変換されます。(c/d)tor から仮想 fn 呼び出しを行うことはできません。その理由は、基本クラスのオブジェクトが作成される時点で、派生クラスの知識がないため、派生クラスを呼び出して、同じロジックが適用される dtors を作成できないためです。