您的位置:首页 > 编程语言 > C语言/C++

C++类对象大小的计算(二)含有虚函数类大小计算

2014-10-01 15:54 281 查看
前一篇文章《C++类对象大小的计算(一)常规类大小计算》初步介绍类大小计算后,我们继续来讨论含有虚函数时类的大小。

以下内存测试环境为Win7+VS2012,操作系统为32位

五、包含虚函数的类

包含虚函数的类,对象生成时,会在类对象当中插入一个指针,这个指针称做虚函数表指针,简称虚表指针(vPtr)。该指针指向一个虚函数表(简称虚表),虚函数表中存储了虚函数的入口地址。基类当中有虚函数时,会产生该虚函数表;创建基类对象,对象中的vPtr会指向该表;调用虚函数时,是通过vPtr在此表当中寻找函数入口地址的。

当派生类继承含有虚函数的子类时,会复制一份虚函数表,派生类如果有与基类中虚函数同名的虚函数,会在虚函数表中覆盖原来基类的虚函数;如果虚函数不重名,只会在虚函数表中增加一个函数入口。这种机制实现了类的多态。

如下面的例子:

#include <iostream>
using namespace std;

class A {
public:
A(int x=0) {
cout<<"A"<<x<<endl;
}
void printA() {
cout<<"Hello A";
}
};
class B :public A{
public:
B(int x=0) {
cout<<"B"<<x<<endl;
}
virtual void printB() {
cout<<"Hello B";
}
};

class C : public B{
public:
C() {
cout<<"C"<<endl;
}
virtual void printC() {
cout<<"Hello C";
}
};

int main() {
A a;
B b;
C c;
cout<<"size of a:"<<sizeof(a)<<endl;
cout<<"size of b:"<<sizeof(b)<<endl;
cout<<"size of c:"<<sizeof(c)<<endl;
return 0;
}

VS类结构图:







运行结果为:



类A没有虚函数,因此大小仍然是1。类B因为有虚函数,其对象当中包含了一个vPtr指针,指针指向类B的虚函数表(假设为vTB),该表中存储了printB的入口地址,因此大小为4。类C因为继承了类B,也就复制了vTB(设为vTC),其对象中也就包含了指向vTC的虚表指针,该虚表中除了有printB的入口地址外,还包含了printC的入口地址,因此,类C对象大小为4。

考虑另一种情况,类C同时继承了类A、B,类A、B当中都有虚函数。如下面的例子:
#include <iostream>
using namespace std;

class A {
public:
A(int x=0) {
cout<<"A"<<x<<endl;
}
virtual void printA() {
cout<<"Hello A";
}
};
class B {
public:
B(int x=0) {
cout<<"B"<<x<<endl;
}
virtual void printB() {
cout<<"Hello B";
}
};

class C : public B, public A{
public:
C() {
cout<<"C"<<endl;
}
void printC() {
cout<<"Hello C";
}
};

int main() {
A a;
B b;
C c;
cout<<"size of a:"<<sizeof(a)<<endl;
cout<<"size of b:"<<sizeof(b)<<endl;
cout<<"size of c:"<<sizeof(c)<<endl;
return 0;
}

VS类结构图:







运行结果为:



类A、B对象的大小按照上面所说的内存很好理解。类C因为同时继承了类A、B,因此就复制了两个虚函数表,也就有了两个vPtr,所以大小为8。如果类C有虚函数,也会放在其中一张虚函数表当中,不会再增加对象大小。
含有成员变量时,按照《C++类对象大小的计算(一)常规类大小计算》所讲内容加上相应的大小即可。

下面的文章《C++类对象大小的计算(三)含有虚函数、虚继承类大小计算》会讨论增加虚继承时,类对象的大小。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: