【问题标题】:Does `__declspec(novtable)` no use?`__declspec(novtable)` 没用吗?
【发布时间】:2019-11-19 10:17:40
【问题描述】:

众所周知,novtable 表示不为纯抽象类创建虚拟表。但是当我运行代码时,出了点问题:

#include <iostream>
using namespace std;

struct A{
    virtual void fun() = 0;
};

struct __declspec(novtable) B{
    virtual void fun() = 0;
};

struct C{
    void fun(){}
};

struct _declspec(novtable) D : public A {};

int main(){
    cout<<sizeof(int*)<<endl;  //4
    cout<<sizeof(A)<<endl;  //4
    cout<<sizeof(B)<<endl;  //4
    cout<<sizeof(C)<<endl;  //1
    cout<<sizeof(D)<<endl;  //4
    return 0;
}

AB 的大小相同,是否意味着novtable 没有用?

ps:用vs2019编译

【问题讨论】:

  • 它禁止指向虚函数的指针列表。仍然在没有novtable的抽象类中使用,它会触发“纯虚函数调用”运行时错误。但仍然保留空间来存储对象中的 vtable 指针。它将被派生的具体类使用。这是一种微优化,在现代机器上几乎没有什么意义。

标签: c++ visual-c++ virtual


【解决方案1】:

docs.microsoft.com 读作:

__declspec(novtable) 阻止编译器生成代码以在类的构造函数和析构函数中初始化 vfptr。在许多情况下,这会删除与类关联的对 vtable 的唯一引用,因此链接器将删除它。

换句话说,vfptr 仍将作为数据成员存在,但其值不会被初始化。例如,如果您设法调用纯虚函数,而不是像“纯虚函数调用”这样的消息,您将得到分段错误。

AB 的大小一样,是不是说明novtable 没用?

__declspec(novtable)的目的不是为了减小对象大小,而是去掉一些你不需要的初始化代码和你也不需要的vtables。

【讨论】:

    【解决方案2】:

    B 类没有 vtable。这并不意味着B 实例的对象中没有vtable 指针。需要 vtable 指针,以便

    例如,如果您创建一个 BDerived 的实例:

    struct BDerived : public B {
        void fun() {}
    };
    
    BDerived bd;
    B* pb = &bd;
    pb->fun();
    

    pb指向一个B子对象,其中包含一个vtable指针,指向BDerived的vtable。当你调用pb-&gt;fun()时,程序会查看pb的vtable指针,跟随它到BDerived的vtable,然后在那个vtable中查找BDerivedfun的实现。


    换句话说,编译器将代码翻译成这样的:

    vtable A_vtable = {NULL};
    struct A {
        vtable *vtable_ptr;
    };
    
    // No vtable, but still a vtable pointer
    struct B {
        vtable *vtable_ptr;
    };
    
    void BDerived_fun() {};
    vtable BDerived_vtable = {&BDerived_fun};
    struct BDerived : public B {
    };
    
    BDerived bd; bd.vtable_ptr = &BDerived_vtable;
    B* pb = &bd;
    (pb->vtable_ptr.fun)(pb);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 2011-11-23
      • 2018-08-05
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多