从虚拟函数的简单到复杂结构有各种各样的情况。什么因素决定了它所需的额外内存数量?例如
class A {virtual void F() {} };
class B : public A {virtual void F() {} };
A和B需要多少内存才能与没有虚函数的类进行比较?另一个有2个虚函数的例子,
class A {virtual void F() {} virtual void G() {} };
class B : public A {virtual void F() {} virtual void G() {} };
和示例3
class A {virtual void F() {}; virtual void G() {} };
class B : public A {virtual void F() {} };
[---------------添加更多有趣的问题------------------]
每个虚方法都有虚拟方法表吗?如果是这样,我认为对于一个类(不是对象,对吧?我认为VPTR是静态的。),有许多虚方法需要一些VPTR,每个VPTR都用于虚方法。右
是否可以为所有虚拟方法只构建一个表,并且只在一个类中放置一个VPTR?
我认为虚拟功能的调用速度应该比手动ifs更快,因为使用了直接的VPTR。右
[--------------- A Test ----------------]
我做了一个测试,并用VS2010和intel c ++编译器显示我的结果。
struct A
{
static int s_i;
int i;
virtual void F() {i+=1;}
virtual void G() {i+=2;}
};
struct B
: public A
{
int j;
virtual void F() {i+=3;}
virtual void G() {i+=4;}
virtual void H() {i+=5;}
};
struct C
: public B
{
virtual void F() {i+=6;}
virtual void H() {i+=7;}
};
TEST(MemoryForVirtualMethod)
{
CHECK_EQUAL(sizeof(A), 8);
CHECK_EQUAL(sizeof(B), 12);
CHECK_EQUAL(sizeof(C), 12);
}
从结果来看,我的结论是
(1)对于具有虚函数的每个对象,添加一个(隐藏指针)VPTR。
(2)对于每个类,为该类的所有虚拟方法构建虚拟方法表。
(3)将VPTR置于对象中是为了实现动态调度,因为引用的类可能不是动态类。
(4)实现调用效率高(比手动ifs快)但牺牲了一些内存。
非常感谢!
答案 0 :(得分:3)
由于虚拟函数通常实现为virtual method table (vtable),因此我猜测每个O(number of virtual functions)
class
和object
一个额外指针。不是你想要的那么精确,但应该给出一个粗略的想法。
正如@AlokSave所提到的那样,还有许多其他细微之处,它们都是特定于编译器的,可能不够一致,无法估计。
通常,编译器为每个类创建一个单独的vtable。创建对象时,会将指向此vtable的指针(称为虚拟表指针,vpointer或VPTR)添加为此对象的隐藏成员
来源:Wikipedia
你覆盖的函数数量(如你的例子中所示)是(我猜测)无关紧要,除非在编译时可以安全地确定要调用的函数,在这种情况下可能是在第二个例子中被视为静态调度函数(G()
)。这也取决于编译器。
编译器通常避免在编译时解析调用时使用vtable。
最后,虚拟功能的成本可能比内存更难。