来宾 网站建设,建筑工人招聘网站怎么做,仿门户网站多功能js相册画廊源码,wordpress好不好用在 C 程序里#xff0c;在有多重继承的类里面。指向派生类对象的基类指针#xff0c;其实是指向了派生类对象里面#xff0c;该基类对象的起始位置#xff0c;该位置相对于派生类对象可能有偏移。偏移的大小#xff0c;等于派生类的继承顺序表里面#xff0c;排在该类前面…在 C 程序里在有多重继承的类里面。指向派生类对象的基类指针其实是指向了派生类对象里面该基类对象的起始位置该位置相对于派生类对象可能有偏移。偏移的大小等于派生类的继承顺序表里面排在该类前面的所有的类的数据成员含虚表指针所占的空间大小总和。
下面以一个简单的程序为例揭示有多重继承关系的派生类对象的内存布局
#include stdio.h
#pragma pack(4)class A {void foo() {}
};class B {
public:virtual void func() {};
private:int b;
};class C {int c;
};class D : public A, public B, public C {
public:void func() override {};
private:int d;
};int main(int argc, const char* argv[]) {D* pd new D();A* pa pd;B* pb pd;C* pc pd;printf(pd%p, pa%p, pb%p, pc%p\nsizeof(A)%zd\nsizeof(B)%zd\nsizeof(C)%zd\nsizeof(D)%zd\n,pd, pa, pb, pc,sizeof(A), sizeof(B),sizeof(C), sizeof(D));return 0;
}
注意该程序用 #pragma pack 指令指示数据在内存中按 4 字节来对齐。在 x64 平台上编译执行结果
$ g test.cc -stdc11
$ ./a.out
pd0x10c0010, pa0x10c0010, pb0x10c0010, pc0x10c001c
sizeof(A)1
sizeof(B)12
sizeof(C)4
sizeof(D)20
我们首先来分析这四个类的大小。
A 只有一个普通函数成员 foo没有任何数据成员是一个空类其大小为 1 字节。之所以空类大小不为零是需要标识类对象在内存中的位置这 1 字节空间仅作占位用不代表任何意义。
B 有一个成员变量 int b 和一个虚函数成员 func其中 b 的大小为 4 字节。 由于存在虚函数因此 B 类起始位置有一个虚表指针(vptr)在 64 平台上指针的大小为 8 字节。因此 B 的大小为 4 8 12 字节。
C 仅有一个成员变量 int c因此其大小也就为 4 字节。
D 继承自A, B, C它的大小等于 A, B, C 的所有数据成员的大小加上其自身的数据成员和虚表指针的总的大小4(b) 4(c) 4(d) 8(vptr) 20 字节。
注意在 D 的继承关系链里面只有基类 B 有虚函数因此对于 D 对象而言总体只有一个虚表指针也就是B基类对象中的虚表指针。如果派生类的多个基类都有虚函数则对应每个有虚函数的基类在派生类对象里都有一个虚表指针。
因此对于分析派生类 D 的对象其内存布局如下 分析结果与程序运行结果一致。