C++ClassSize(C++类⼤⼩)
C++ Class Size (C++ 类⼤⼩)
最近在写B+Tree的时候突然发现对类节点的⼤⼩没算准,导致不知道固定⼤⼩的内存可以存⼏个节点。Google上得到了不少资料,先加以整理并加⼊⼀些⾃⼰的测试;⼀下都是linux环境输出的记过,windows vc++输出结果会不⼀样的,原⽂出处:,windows相关的是我⾃⼰添加上去的。
涉及到c++中求类⼤⼩时需要特别注意⼀下⼏点
sizeof 指针1.为类的⾮静态成员数据的类型⼤⼩之和.
2.有编译器额外加⼊的成员变量的⼤⼩,⽤来⽀持语⾔的某些特性(如:指向虚函数的指针、虚继承、多重继承).
3.为了优化存取效率,进⾏的边缘调整.
4.  与类中的构造函数,析构函数以及其他的成员函数⽆关.
5.  私有继承,会去继承之前的私有成员变量么? 会...在内存中仍然分配相应的空间,只是在⼦类中是不可见的!
6.  在做多层次的继承类⼤⼩时某个⼦类的类⼤⼩总是等于⽗类的⼤⼩加上⼦类中数据成员和是否有虚函数,是否是虚继承等因素来决定。
空类⼤⼩为1
⾸先:我们要知道什么是类的实例化,所谓类的实例化就是在内存中分配⼀块地址.
那我们先看看⼀个例⼦:
#include<iostream.h>
class a {};
class b{};
class c:public a{
virtual void fun()=0;
};
class d:public b,public c{};
int main()
{
cout<<"sizeof(a)"<<sizeof(a)<<endl;
cout<<"sizeof(b)"<<sizeof(b)<<endl;
cout<<"sizeof(c)"<<sizeof(c)<<endl;
cout<<"sizeof(d)"<<sizeof(d)<<endl;
return 0;}
程序执⾏的输出结果为:
sizeof(a) =1
sizeof(b)=1
sizeof(c)=4
sizeof(d)=8
上⾯是在VC++6.0编译的结果,但是在Dev-C++和Code::Blocks下得出的结果是 sizeof( d ) = 4
为什么会出现这种结果呢?初学者肯定会很烦恼是吗?类a,b明明是空类,它的⼤⼩应该为为0,为什么 编译器输出的结果为1呢?这就是我们刚才所说的实例化的原因(空类同样可以被实例化),每个实例在内存中都有⼀个独⼀⽆⼆的地址,为了达到这个⽬的,编译器往往会给⼀个空类隐含的加⼀个字节,这样空类在实例化后在内存得到了独⼀⽆⼆的地址.所以a,b的⼤⼩为1.
虚函数
[cpp]
#include<iostream>
using namespace std;
class A
{
public:
virtual void aa(){}
private:
char k[3];
};
class B: public A
{
public:
virtual void bb(){}
};
int main()
{
cout<<"A's size is "<<sizeof(A)<<endl;
cout<<"B's size is "<<sizeof(B)<<endl;
return 0;
}
VS和gcc下执⾏结果:
A's size is 8
B's size is 8
说明:有虚函数的类有个virtual table(虚函数表),⾥⾯包含了类的所有虚函数,类中有个virtual table pointers,通常成为vptr指向这个virtual table,占⽤4个字节的⼤⼩。成员类B public继承于A,类B的虚函数表⾥实际上有两个虚函数A::aa()和B::bb(),类B的⼤⼩等于char k[3]的⼤⼩加上⼀个指向虚函数表指针vptr的⼤⼩,考虑内存对齐为8。但是这⾥有⼀点,当class B是public virtual A,这样的话si
zeof(B)就是16除了需要⼀个指向虚继承⽗类的指针之外,由于⽗类的虚函数是aa(),⼦类的虚函数是bb(),所以好像是B⾥⾯建了两个虚表,⼀个是继承A类的aa(),⼀个是B类的bb(),如果A和B⾥⾯的虚函数都是aa的话,这个B的⼤⼩将会是12.
虚继承
[cpp]
#include<iostream>
using namespace std;
class A
{
public:
virtual void aa(){}
private:
char k[3];
};
class B: virtual public A
{
public:
virtual void bb(){}
};
int main()
{
cout<<"A's size is "<<sizeof(A)<<endl;
cout<<"B's size is "<<sizeof(B)<<endl;
return 0;
}
vs和gcc下
执⾏结果:
A's size is 8
B's size is 12
说明:类B⾥包含,继承的char k[3],继承的虚函数,类B的虚函数表⾥有A::aa(),因为是虚继承,还有⼀个指向⽗类的指针,该指针为指向虚基类的指针(Pointer to virtual base class)。考虑内存对齐,总⼤⼩为12。这⾥要特别指明⼀下,在windows下,B's size is 16,貌似在windows⾥虚继承还会有⼀个4字节的什么东西的这个应该和编译器有关系了。
多重继承
#include <iostream>
using namespace std;
class A
{
char k[3];
public:
virtual void aa(){};
};
class B
{
char q[3];
public:
virtual void bb();
};
class C: public A,public B
{
char j[3];
public:
virtual void cc(){};
};
int main()
{
cout<<"sizeof(A):"<<sizeof(A)<<endl;
cout<<"sizeof(B):"<<sizeof(B)<<endl;
cout<<"sizeof(C):"<<sizeof(C)<<endl;
return 0;
}
像这种继承⽅式,在类C中会维护两个虚函数指针,第⼀个指向第⼀个基类的虚函数表(并且带上在类C中定义的虚函数),第⼆个指针指向第⼆个基类(B)的虚函数表...其他的类似。
综合例⼦:
#include <iostream>
using namespace std;
class A
{
char k[3];
public:
virtual void f(){};
};
class B : public virtual A
{
char i[3];
public:
virtual void f1(){};
};
class C: public virtual  A{
//virtual void f(){};
char j[3];
public:
virtual void t(){};
};
class D: public B,public C
{
char g[3];
public:
virtual void s();
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
cout<<sizeof(D)<<endl;
return 0;
}
最后得到的结果是  8 16 16 28 (windows⾥是8 20 20 36,参照上述虚继承⼦类和⽗类续函数不⼀样导致的)
最主要的是sizeof(D): 4个char数组,对齐后是16,⼜是多重继承,那么有两个虚函数表的指针,⼜需要维护⼀分A类的指针,那么是
16+4*2+采⽤虚继承,⽬的就是为了解决⼆义性和减⼩内存开销,所以在D中只维护⼀份A的指
针便可。
在来插⼀句,有很多同学都觉得很奇怪,为什么类⾥⾯成员函数不占内存,其实成员函数和普通函数⼀样的都在内存,只不过分配在代码段⽽已,所以sizeof没有计算出来;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。