概述
#pragma pack(4)
class CAnimal
{
public:
char name[3];
short age;
int color;
char gender;
};
class CDog : public CAnimal
{
public:
int hurt;
};
void mem_offset()
{
CAnimal animal;
CDog dog;
cout << "-----animal-----" << endl;
cout << "sizeof(animal) = " << sizeof(animal) << endl;
cout << "name offset = " << (char*)animal.name - (char*)&animal << endl;
cout << "age offset = " << (char*)&animal.age - (char*)&animal << endl;
cout << "color offset = " << (char*)&animal.color - (char*)&animal << endl;
cout << "gender offset = " << (char*)&animal.gender - (char*)&animal << endl;
cout << "-----dog-----" << endl;
cout << "sizeof(dog) = " << sizeof(dog) << endl;
cout << "name offset = " << (char*)dog.name - (char*)&dog << endl;
cout << "age offset = " << (char*)&dog.age - (char*)&dog << endl;
cout << "color offset = " << (char*)&dog.color - (char*)&dog << endl;
cout << "gender offset = " << (char*)&dog.gender - (char*)&dog << endl;
cout << "hurt offset = " << (char*)&dog.hurt - (char*)&dog << endl;
}
output:
-----animal-----
sizeof(animal) = 16
name offset = 0
age offset = 4
color offset = 8
gender offset = 12
-----dog-----
sizeof(dog) = 20
name offset = 0
age offset = 4
color offset = 8
gender offset = 12
hurt offset = 16
分析:
- 每个类会生成对应的c struct,c struct中的数据成员在内存中布局顺序与数据成员在类定义中的顺序一致
- 子类的c struct在父类的c struct末尾添加自身的数据成员
类的这种内存布局确保了子类不会改变父类数据成员相对于父类struct首地址的offset,因此把子类指针赋值给父类指针是安全的,因为父类指针通过数据成员的offset能寻址到正确的内存空间
类隐式转换
子类指针隐式转换为父类指针是安全的,引用的本质是const对象,因此子类赋值给父类引用也是安全的
class CAnimal
{
public:
CAnimal()
{
cout << "CAnimal()" << endl;
}
CAnimal(const CAnimal &other)
{
cout << "CAnimal(const CAnimal &other)" << endl;
}
public:
CAnimal& operator=(const CAnimal &other)
{
cout << "CAnimal operator=" << endl;
return *this;
}
public:
void info()
{
cout << "CAnimal info()" << endl;
}
};
class CDog : public CAnimal
{
public:
CDog()
{
cout << "CDog()" << endl;
}
CDog(const CDog &other) : CAnimal(other)
{
cout << "CDog(const CDog &other)" << endl;
}
public:
CDog& operator=(const CDog &other)
{
CAnimal::operator=(other);
cout << "CDog operator=" << endl;
return *this;
}
};
void class_convert()
{
CDog dog;
CAnimal* pAnimal = &dog;
CAnimal* rAnimal = &dog;
pAnimal->info();
rAnimal->info();
CAnimal animal = dog;
animal = dog;
}
output:
CAnimal()
CDog()
CAnimal info()
CAnimal info()
CAnimal(const CAnimal &other)
CAnimal operator=
结论:
- 子类对象初始化父类对象的本质是调用父类的复制构造函数
- 子类对象赋值给父类对象的本质是调用父类的赋值操作符函数