做整合營銷的網(wǎng)站企業(yè)網(wǎng)站推廣模式
在 C++ 程序里,在有多重繼承的類里面。指向派生類對象的基類指針,其實是指向了派生類對象里面,該基類對象的起始位置,該位置相對于派生類對象可能有偏移。偏移的大小,等于派生類的繼承順序表里面,排在該類前面的所有的類的數(shù)據(jù)成員(含虛表指針)所占的空間大小總和。
下面以一個簡單的程序為例,揭示有多重繼承關(guān)系的派生類對象的內(nèi)存布局:
#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\n""sizeof(A)=%zd\n""sizeof(B)=%zd\n""sizeof(C)=%zd\n""sizeof(D)=%zd\n",pd, pa, pb, pc,sizeof(A), sizeof(B),sizeof(C), sizeof(D));return 0;
}
注意該程序用 #pragma?pack 指令指示數(shù)據(jù)在內(nèi)存中按 4 字節(jié)來對齊。在 x64 平臺上編譯執(zhí)行結(jié)果:
$ g++ test.cc -std=c++11
$ ./a.out
pd=0x10c0010, pa=0x10c0010, pb=0x10c0010, pc=0x10c001c
sizeof(A)=1
sizeof(B)=12
sizeof(C)=4
sizeof(D)=20
我們首先來分析這四個類的大小。
A 只有一個普通函數(shù)成員 foo,沒有任何數(shù)據(jù)成員,是一個空類,其大小為 1 字節(jié)。之所以空類大小不為零,是需要標識類對象在內(nèi)存中的位置,這 1 字節(jié)空間僅作占位用,不代表任何意義。
B 有一個成員變量 int b 和一個虛函數(shù)成員 func,其中 b 的大小為 4 字節(jié)。 由于存在虛函數(shù),因此 B 類起始位置有一個虛表指針(vptr),在 64 平臺上指針的大小為 8 字節(jié)。因此 B 的大小為 4 + 8 = 12 字節(jié)。
C 僅有一個成員變量 int c,因此其大小也就為 4 字節(jié)。
D 繼承自A, B, C,它的大小等于 A, B, C 的所有數(shù)據(jù)成員的大小,加上其自身的數(shù)據(jù)成員和虛表指針的總的大小:4(b) + 4(c) + 4(d) + 8(vptr) = 20 字節(jié)。
注意:在 D 的繼承關(guān)系鏈里面,只有基類 B 有虛函數(shù),因此對于 D 對象而言,總體只有一個虛表指針,也就是(B)基類對象中的虛表指針。如果派生類的多個基類都有虛函數(shù),則對應(yīng)每個有虛函數(shù)的基類,在派生類對象里都有一個虛表指針。
因此,對于分析派生類 D 的對象,其內(nèi)存布局如下:
分析結(jié)果與程序運行結(jié)果一致。