pax*_*977 11 c++ rtti visual-studio visual-c++ compiler-specific
或者,使用__declspec(novtable)是否还有其他已知的负面影响?我似乎无法找到任何问题的参考.
Own*_*loo 10
MSCV用于one vptr per object and one vtbl per class实现OTI 机制,如RTTI和虚函数.
因此,当且仅当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) );
Run Code Online (Sandbox Code Playgroud)
使用时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.
}
};
Run Code Online (Sandbox Code Playgroud)
注意:虚拟f()= 0; 使f成为a pure virtual function和B成为抽象类.
该definition纯虚函数的could(未must)丢失.
C++允许在构造函数中调用虚函数,我们不建议这样做.
更新: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
};
Run Code Online (Sandbox Code Playgroud)
但是vptr在构造过程中是不确定的.这是构造函数中不建议使用虚函数调用的原因之一.
如果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.
因此this->f();调用D2 :: f()并违反三个断言.
| 归档时间: |
|
| 查看次数: |
5740 次 |
| 最近记录: |