一个类的大小和数据成员有很大的关系,总结下sizeof(类)的各种情况
首先看一个空类的大小:
class A{};
int main(){
cout<<sizeof(A)<<endl;//输出结果1
return 0;
}
类中没有任何成员变量,sizeof(A)的结果是1,书上说编译器插入了一个char,使得这个class的不同实体在内存中配置独一无二的地址。
在类中添加构造和析构函数,看起来类中添加了函数,大小会不会变化呢?
class A{
public:
A();
~A();
};
int main(){
cout<<sizeof(A)<<endl;//输出还是1
return 0;
}
结果还是1,就是说类的析构函数没有存放在类的对象空间,其实不管是全局函数还是成员函数,都是存放在代码区,所以不占类的空间,在类中定义成员函数或者在成员函数中定义变量,都不会影响类的大小。但是虚函数是通过一张虚函数表来来实现的,编译器要保证虚函数表的指针存在于对象实例中最前面的位置,这是为了正确取到虚函数的偏移量:
class A{
virtual int fun(){};
};
int main(){
cout<<sizeof(A)<<endl; //输出4
return 0;
}
在类中定义变量又是如何影响大小的?
class A{
int a;
char b;
char c;
};
class B{
char b;
int a;
char c;
};
int main(){
cout<<sizeof(A)<<endl;//输出8
cout<<sizeof(B)<<endl;//输出12
return 0;
}
在32位编译器中,int占4个字节,char占一个字节,A中本来应该是占6个字节的,实际上为了空间和复杂度上的平衡采用了内存对齐,按照以下三个条件来计算大小:
1. 结构体(类)的首地址能够被其最宽的基本类型成员大小所整除
2. 每个成员相对于首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间填充字节
3. 结构体的总大小为最宽的基本类型大小的整数倍,如有需要编译器会在最后一个成员之后加上填充字节
对于A的大小:
****|**** 8字节
int(4) | char(1)char(1)+两字节填充 8字节
对于B的大小
****|****|**** 12字节
char(1)+3填充字节 | int(4) | char(1)+3填充字节 12字节
这就是相同成员变量占用不同内存大小的原因。下面在看一个例子:
class A{
static int a;
char c;
char d;
};
int main(){
cout<<sizeof(A)<<endl; //输出2
return 0;
}
由于静态变量在全局区存放,在类域中为所有对象共享,不属于任何对象,所以int a不占类大小。有继承关系的类的大小:
class A{
int a;
char c;
char d;
};
class B:A{
char e;
int b;
};
int main(){
cout<<sizeof(A)<<endl; //输出8
cout<<sizeof(B)<<endl; //输出16
return 0;
}
A根据上面所说的内存对齐大小为8,B也需要内存对齐,并且继承了A,所以大小为A+B = 16;