关于 __declspec(novtable) 的疑问,欢迎高手参与讨论

stone_dongdong 2010-12-25 01:10:40
一直觉得 __declspec(novtable) 到底有没有必要,感觉纯粹是多此一举的关键词。
MSDN上说是给纯接口类用的,可以显著减少编译后程序的大小。
但是我感觉,程序减少大小跟 __declspec(novtable) 声明毫无关系啊,把接口类定义成纯虚函数本来就是减少程序大小了,跟加没加 __declspec(novtable) 有啥关系呢。比如:
class Base
{
public:
virtual BaseFunc1() = 0;
virtual BaseFunc2() = 0;
}
class Derive : public Base
{
public :
virtual BaseFunc1() {}
virtual BaseFunc2() {}
virtual DeriveFunc1(){}
}

Derive* obj = new Derive;
这种继承关系下,obj也就是一个虚函数表,也就是3个虚函数项目而已,如果在 Base类前面加了 __declspec(novtable) ,内存占用还是这样而已。有啥分别?
并且如果 Base中有某个虚函数的实现,Derive中又重载了此函数的实现,那么虚函数表还是一个,虚函数项目还是那么多。生成文件/内存占用中仅仅多的是Base的此虚函数的函数体代码罢了。
我就感觉 __declspec(novtable) 纯粹是一个修饰,就跟 MFC中的 afx_msg 一样,用来表意的罢了。
不知各位还有什么看法,欢迎讨论。
...全文
289 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
CrazyAsk 2012-10-22
  • 打赏
  • 举报
回复
解析的不错
hideforever 2012-09-26
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

Mircrosoft c++中提供了__declspec(novtable)来修饰一个类,来表示该类没有虚函数表,也就是虚函数都是纯虚的。减小SIZE 是因为虚表是需要空间的,在不需要虚表的情况下,把虚表去掉就可以减少SIZE了。

C++中的虚函数的实现一般是通过虚函数表来实现的,类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。

纯虚函数:在基类中不能对虚函数给……
[/Quote]
已经说得很明白了
healer_kx 2011-01-04
  • 打赏
  • 举报
回复
有用,要不ATL也不会大量用了。
Sou2012 2011-01-04
  • 打赏
  • 举报
回复
V TA B L E(虚函数表)和VPTR(指向虚函数标的指针)的区别

编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟。
编译器对每个包含虚函数的类创建一个表(称为V TA B L E)。在V TA B L E中,编译器放置特定类的虚函数地址。在每个带有虚函数的类中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E。通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。为每个类设置V TA B L E、初始化V P T R、为虚函数调用插入代码,所有这些都是自动发生的,所以我们不必担心这些。利用虚函数,这个对象的合适的函数就能被调用,哪怕在编译器还不知道这个对象的特定类型的情况下。(《C++编程思想》)
Sou2012 2011-01-04
  • 打赏
  • 举报
回复
__declspec(novtable) 在C++中接口中广泛应用. 不容易看到它是因为在很多地方它都被定义成为了宏. 比如说ATL活动模板库中的ATL_NO_VTABLE, 其实就是__declspec(novtable).

__declspec(novtable) 就是让类不要有虚函数表以及对虚函数表的初始化代码, 这样可以节省运行时间和空间. 但是这个类一定不允许生成实例, 因为没有虚函数表, 就无法对虚函数进行调用. 因此, __declspec(novtable)一般是应用于接口(其实就是包含纯虚函数的类), 因为接口包含的都是纯虚函数, 不可能生成实例. 我们把 __declspec(novtable)应用到接口类中, 这些接口类就不用包含虚函数表和初始化虚函数表的代码了. 它的派生类会自己包含自己的虚函数表和初始化代码.
stone_dongdong 2011-01-04
  • 打赏
  • 举报
回复
没人回答?郁闷
信阳毛尖 2011-01-04
  • 打赏
  • 举报
回复
Mircrosoft c++中提供了__declspec(novtable)来修饰一个类,来表示该类没有虚函数表,也就是虚函数都是纯虚的。减小SIZE 是因为虚表是需要空间的,在不需要虚表的情况下,把虚表去掉就可以减少SIZE了。

C++中的虚函数的实现一般是通过虚函数表来实现的,类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。

纯虚函数:在基类中不能对虚函数给出有意义的实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用,(这应该不难理解吧?)
  • 打赏
  • 举报
回复
struct __declspec( dllexport ) A
{
virtual void func()=0;
};
struct __declspec( dllexport ) __declspec(novtable) B : public A
{

};

struct __declspec( dllexport ) C : public B
{
virtual void func()
{
}
};

用dependency walker查看
A::A(void)
A::A(struct A const &)
struct A & A::operator=(struct A const &)
B::B(void)
B::B(struct B const &)
struct B & B::operator=(struct B const &)
void C::func(void)
C::C(void)
C::C(struct C const &)
struct C & C::operator=(struct C const &)
const A::`vftable'
const C::`vftable'

去掉__declspec(novtable)则为
A::A(void)
A::A(struct A const &)
struct A & A::operator=(struct A const &)
B::B(void)
B::B(struct B const &)
struct B & B::operator=(struct B const &)
void C::func(void)
C::C(void)
C::C(struct C const &)
struct C & C::operator=(struct C const &)
const A::`vftable'
const B::`vftable' //<=====区别在这里
const C::`vftable'
stone_dongdong 2011-01-04
  • 打赏
  • 举报
回复
ilysony
谢谢你的回答,不过好像你没明白我问的意思。
我说加 __declspec(novtable) 跟不加效果是一样,怀疑这个关键词的有用性。

我就是想知道 __declspec(novtable) 到底有啥用啊?

16,550

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧