C++ 类对象大小计算(二)含有虚函数类
2018-01-13 16:49
423 查看
五、包含虚函数的类
包含虚函数的类,对象生成时,会在类对象当中插入一个指针,这个指针称做虚函数表指针,简称虚表指针(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;
}
运行结果为:
类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";
}
};
4000
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;
}运行结果为:
类A、B对象的大小按照上面所说的内存很好理解。类C因为同时继承了类A、B,因此就复制了两个虚函数表,也就有了两个vPtr,所以大小为8。如果类C有虚函数,也会放在其中一张虚函数表当中,不会再增加对象大小。
包含虚函数的类,对象生成时,会在类对象当中插入一个指针,这个指针称做虚函数表指针,简称虚表指针(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;
}
运行结果为:
类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";
}
};
4000
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;
}运行结果为:
类A、B对象的大小按照上面所说的内存很好理解。类C因为同时继承了类A、B,因此就复制了两个虚函数表,也就有了两个vPtr,所以大小为8。如果类C有虚函数,也会放在其中一张虚函数表当中,不会再增加对象大小。
相关文章推荐
- C++类对象大小的计算(二)含有虚函数类大小计算
- C++ 类对象大小计算(一)常规情况
- C++类对象大小的计算(三)含有虚函数、虚继承类大小计算
- 怎样计算C++继承、虚继承、虚函数类的大小
- sizeof计算含有虚函数的类对象的大小
- 1)C++对象大小计算
- C++回顾之static成员、static成员函数及类对象大小计算
- C++回顾之static成员、static成员函数及类对象大小计算
- 三十二、C++内存布局,对象大小计算、虚函数虚继承对类内存模型的影响
- 怎样计算C++继承、虚继承、虚函数类的大小
- 使struct对象拥有可变大小的数组——(C++深度探索)
- C++ 内存对齐 (计算结构体的大小)
- c++带有虚函数的对象的大小问题
- Java中计算对象的大小
- 面向对象课程 - 寒假第四次作业 - C++计算器项目计算部分
- Java对象结构及大小计算
- C++中类对象所占空间的大小
- c++中实例化对象的大小(转)
- C++中虚函数工作原理和(虚)继承类的内存占用大小计算
- C++中虚函数工作原理和(虚)继承类的内存占用大小计算