C++ 虚拟函数需要多少字节的额外内存?
虚函数的结构从简单到复杂,有各种各样的情况。什么因素决定了所需的额外内存数量?比如说C++ 虚拟函数需要多少字节的额外内存?,c++,memory,virtual-functions,C++,Memory,Virtual Functions,虚函数的结构从简单到复杂,有各种各样的情况。什么因素决定了所需的额外内存数量?比如说 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 : pu
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() {} };
[--------------添加更多有趣的问题----------------]
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更快),但会牺牲一些内存
非常感谢 由于虚拟函数通常是作为一个对象实现的,所以我猜每个
类都有O(虚拟函数的数量)
个,每个对象都有一个额外的指针。没有你想要的那么精确,但应该给出一个大致的想法。
正如@AlokSave所提到的,还有许多其他细节是非常特定于编译器的,可能不足以进行估计
通常,编译器为每个类创建一个单独的vtable。创建对象时,将添加一个指向此vtable的指针,称为虚拟表指针vpointer或VPTR,作为此对象的隐藏成员
资料来源:
您重写的函数的数量(如示例中所示)是(即时猜测)无关的,除非在编译时可以安全地确定要调用的函数,在这种情况下,它可能被视为静态分派函数(G()
,在第二个示例中)。这也取决于编译器
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);
}
编译器通常避免在编译时解析调用时使用vtables
最后,虚拟功能的成本在速度上可能比内存更高 这将取决于您的编译器和平台。哪些是你感兴趣的?VS2010还是英特尔C++,谢谢。这信息对你来说有什么关系?不应该!如果您需要动态调度,您只需使用virtual
就可以了。这里没有任何开销。您只需为您使用的东西付费。您使用的功能只需支付成本。仅此而已。@PhilipKendall:只是好奇,您知道有多少编译器不使用vtable方法?@AlokSave:这可能很重要。例如,您可以通过不使用vtable并增加对象的内存占用来删除一级间接寻址。毕竟,了解细节是件好事。无知的方法并不是最好的。“因为虚拟函数是作为vtable实现的”,虽然不一定。这完全是实现定义的细节。此外,每个类是否有一个vtable或多个vtable因实现而异。尽管vtable和vpointer机制是实现动态调度的最常见的方法,但所涉及的vtable的数量并不是一个一致的细节。@AlokSave修复了这个问题,我可以发誓,当我写这篇文章时,我脑子里有一个典型的想法:P