You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

__declspec(novtable)是否无效?VS2019纯虚类大小测试存疑

为什么加了__declspec(novtable)的纯抽象类和普通纯抽象类大小一样?

你这个疑惑其实源于对__declspec(novtable)作用的常见误解——它不是用来移除类对象里的虚表指针,而是用来阻止编译器为这个纯抽象类生成实际的虚表数据。

先解释为什么sizeof(A)和sizeof(B)相同

不管有没有加novtable,只要类里声明了虚函数(包括纯虚函数),C对象的内存布局里就会保留一个虚表指针的位置——这是C实现多态的基础机制,和novtable的作用无关。在你的32位编译环境下,指针大小是4字节,所以A和B的大小自然都是4字节。

__declspec(novtable)的真正作用

纯抽象类本来就是用来做接口的,理论上永远不会被实例化,但默认情况下编译器还是会为它生成一个虚表(哪怕里面的纯虚函数没有具体实现)。novtable的作用就是告诉编译器:"这个类不会被实例化,不用给它生成虚表了"。这么做的好处是:

  • 减少最终可执行文件的体积,避免冗余的虚表数据;
  • 如果不小心尝试实例化这个类(比如代码写错了),链接阶段会直接报错(因为找不到虚表),比运行时崩溃更直观。

结合你的代码看差异

  • 对于struct A:编译器会为它生成一个虚表,里面包含纯虚函数fun()的条目;
  • 对于struct __declspec(novtable) B:编译器不会生成B的虚表,但B的对象布局依然保留虚表指针的位置(因为有纯虚函数),所以大小不变;
  • 对于struct _declspec(novtable) D : public A:D继承了A的纯虚函数,同样编译器不会为D生成虚表,直到有子类继承D并实现fun(),此时子类的虚表会被正常生成。

验证novtable作用的小实验

如果你尝试在代码里实例化B:

B b; // 编译可能通过,但链接时会报错:无法解析的外部符号 __imp_??_7B@@6B@(B的虚表)

而尝试实例化A的话,编译阶段就会直接报错:无法实例化抽象类——这也能侧面看出两者的区别,novtable把错误时机从编译推迟到了链接,但核心是避免了无用的虚表生成。

总结一下:novtable不影响对象的内存布局(所以大小不变),它管的是虚表这个全局数据结构是否被编译器生成,这才是它的核心作用。

内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:41:31