喜欢的朋友可以关注收藏一下: http://blog.csdn.NET/qq_31201973
本文如有错误,请及时私信我。
原版要求:
分别给出下面的类型Fruit和Apple的类型大小(即对象size),并通过画出二者对象模型图以及你的测试来解释该size的构成原因。
class Fruit{test
int no;
double weight;
char key;
public:
void print() { }
virtual void process(){ }
};
class Apple: public Fruit{
int size;
char type;
public:
void save() { }
virtual void process(){ }
};
Fruit的类型大小(即对象size):32
Apple的类型大小(即对象size):40
(win10,vs2013编译有效)
对象模型图(字节对齐,虚基类表指针字节对齐):
上图是我根据测试得出的对齐模型表
在c++对象模型中会有对齐规则:
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中的n就是你要指定的“对齐系数”。
规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐 按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的 数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
除了这三条规则之外虚指针会单独对齐:
类Fruit有虚函数,所以会有一个隐藏的成员,虚函数表指针,放在类对象的最开始的地方,因为类Fruit的最大对齐参数就是隐藏成员本身的对齐参数8了,所以在后面补充4个字节。然后就是成员变量no,后面是weight对齐参数是8,所以在no后面补充四个字节,然后是key,对齐系数是1,所以紧跟在后面。因为Fruit本身也要自身对齐,按照它的成员中最大的那个有效对齐作为自己的自身对齐,也就是weight,所以Fruit本身要按照8字节对齐,所以在key后面要填充7个字节才满足对齐规则。
sizeof(Fruit)=4+4+4+4+8+1+7=32 √
类Apple有虚函数,所以会有一个隐藏的成员,虚函数表指针,放在类对象的最开始的地方,因为类Apple的最大对齐参数就是隐藏成员本身的对齐参数8了,所以在vptr后面补充4个字节。然后就是成员变量no,后面是weight对齐参数是8,所以在no后面补充四个字节,然后是key,对齐系数是1,所以紧跟在后面,然后是size,对齐系数是4所以补充3个字节,然后是type对齐系数是1紧跟在后面。因为Apple本身也要自身对齐,按照它的成员中最大的那个有效对齐作为自己的自身对齐,也就是weight,所以Fruit本身要按照8字节对齐,所以在key后面要填充7个字节才满足对齐规则。
sizeof(Apple)=4+4+4+4+8+1+3+4+1+7=40 √
测试代码:
#include<iostream>
using namespace std;
class Fruit{
protected:
int no;
double weight;
char key;
public:
void print() {
cout << "sizeof(f1.no)=" << sizeof(this->no) << endl;
cout << "sizeof(f1.weight)=" << sizeof(this->weight) << endl;
cout << "sizeof(f1.key)=" << sizeof(this->key) << endl;
}
const int* get_no() const { return &no; }
const double* get_weight() const { return &weight; }
const char* get_key() const { return &key; }
virtual void process(){ }
};
class Apple : public Fruit{
protected:
int size;
char type;
public:
void print() {
cout << "sizeof(a1.no)=" << sizeof(this->no) << endl;
cout << "sizeof(a1.weight)=" << sizeof(this->weight) << endl;
cout << "sizeof(a1.key)=" << sizeof(this->key) << endl;
cout << "sizeof(a1.no)=" << sizeof(this->size) << endl;
cout << "sizeof(a1.weight)=" << sizeof(this->type) << endl;
}
void save() { }
const int* get_size() const { return &size; }
const char* get_type() const { return &type; }
virtual void process(){ }
};
int main()
{
Fruit f1;
Apple a1;
int* pf1 = (int*)&f1;
int* pa1 = (int*)&a1;
cout <<"Fruit类vptr的大小:"<< sizeof(pf1) << endl;
f1.print();
cout << "Fruit类大小:sizeof(f1)=" << sizeof(f1) << endl;
cout << "Fruit类vptr的地址:" << pf1 << endl;
cout << "Fruit类no的地址:" << f1.get_no() << endl;
cout << "Fruit类weight的地址:" << f1.get_weight() << endl;
cout << "Fruit类key的地址:" << (int*)(f1.get_key()) << endl;
cout << "Fruit类vtbl的地址:" << (int*)(*pf1) << endl;
cout << "Fruit::process()的地址:" << (int*)*((int*)(*pf1)) << endl;
cout << "——————————————————————————" << endl;
cout << "Apple类vptr的大小:" << sizeof(pa1) << endl;
a1.print();
cout << "Apple类大小:sizeof(a1)=" << sizeof(a1) << endl;
cout << "Apple类vptr的地址:" << pa1 << endl;
cout << "Apple类no的地址:" << a1.get_no() << endl;
cout << "Apple类weight的地址:" << a1.get_weight() << endl;
cout << "Apple类key的地址:" << (int*)(a1.get_key()) << endl;
cout << "Apple类size的地址:" << a1.get_size() << endl;
cout << "Apple类type的地址:" << (int*)(a1.get_type()) << endl;
cout << "Apple类vtbl的地址:" << (int*)(*pa1) << endl;
cout << "Apple::process()的地址:" << (int*)*((int*)(*pa1)) << endl;
getchar();
return 0;
}
测试结果:
参考资料:
1. http://blog.csdn.net/haoel/article/details/1948051/
2. http://blog.csdn.net/chengonghao/article/details/51679743
3.http://blog.csdn.net/hairetz/article/details/4084088
4. http://www.jb51.net/article/36903.htm