首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在抽象基类上使用__declspec(novtable)会以任何方式影响RTTI吗?

在抽象基类上使用__declspec(novtable)会以任何方式影响RTTI吗?
EN

Stack Overflow用户
提问于 2009-11-26 10:33:52
回答 2查看 6.9K关注 0票数 14

或者,使用__declspec(novtable)还有其他已知的负面影响吗?我似乎找不到任何问题的参考。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-12-03 05:49:51

MSCV使用one vptr per object and one vtbl per class实现面向对象的机制,如RTTI和虚函数。

因此,如果且仅当正确设置了vptr时,RTTI和虚拟函数才能正常工作。

代码语言:javascript
复制
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) );

当使用__declspec(novtable)时,B应该是一个抽象类。

除了在D1的构造函数中,没有B的实例。

__declspec(novtable)在大多数情况下没有负面影响。

但在派生类的构造过程中,__declspec(novtable)会使其不同于C++语义。

代码语言:javascript
复制
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.
    }
};

注意:虚拟f() = 0;使f成为一个pure virtual function,使B成为一个抽象类。

缺少纯虚函数could (不是must)的definition

C++允许在构造函数中调用虚函数,这是我们不推荐的。

更新: D2中的错误:派生构造函数中的vptr。

代码语言:javascript
复制
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在构造过程中是不确定的,这也是不推荐在构造函数中调用虚函数的原因之一。

如果D2::D2()中的vptr为B,并且缺少B::f()的定义,则在vtbl中取消引用指向函数的指针时,this->f();将崩溃。

如果D2::D2()中vptr为B,且B使用novtable,则在取消引用未初始化的vptr时,this->f();将崩溃。

实际上,D2:: D2 ()中vptr在MSVC(Msvc8)中是D2,在执行D2::D2()中的其他代码之前,.The编译器将vptr设置为D2。

因此this->f();调用D2::f(),这三个断言将被违反。

票数 11
EN

Stack Overflow用户

发布于 2011-02-24 00:22:37

如果我理解正确的话:在ctor或dtor中的任何虚拟fn调用都会转换为编译时链接。我们不能从(c/d)tor进行虚拟fn调用。原因是,在创建基类的对象时,它不知道派生类,因此无法调用派生类并应用相同的逻辑。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1801258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档