VC6 實測類別大小
class X {}; // 1
class Y : public virtual X {}; // 4
class Z : public virtual X {}; // 4
class A : public Y, public Z {}; // 8
大小推導
X:空類別插入 1 byte 佔位符。
Y:虛繼承含指向虛基類指標 (4B) + 虛基類佔位 (1B) + 對齊填充 (3B) = 8B。VC6 最佳化:empty virtual base class 視為衍生類開頭一部分,省去 1B 及對齊,**實測 4B**。
Z:同 Y,4B。
A:共享單一 X 實體 (1B) + Y 非虛部分 (4B) + Z 非虛部分 (4B) = 9B → 對齊填充 3B = 12B。VC6 最佳化移除 X 佔位,**實測 8B**。
資料成員綁定規則
- 成員函數參數名稱在首次遇見時決議。若嵌套
typedef 在參考**之後**出現,編譯器報錯。防禦風格:所有資料成員前置宣告。
- Inline 函數本體在**整個類別宣告完成後**才分析求值。
資料成員佈局
- 同一存取區段 (public/protected/private) 內順序 = 宣告順序。
- 不同區段順序編譯器可自由調整 (實務上不調整)。
- 編譯器合成成員 (如
vptr) 穿插其中。
資料成員存取
- 靜態成員:唯一實體在全域資料段,存取轉為直接參考。取址得普通指標非成員指標。
- 非靜態成員:
obj.member 編譯期固定位移;ptr->member 若涉及虛基類成員,位移需執行期透過虛基類表/指標間接存取。
繼承對佈局影響
- 單一繼承無多態:衍生類 = 基類成員 + 自身成員。但分層宣告會導致對齊填充累積 (如
Concrete3 16B vs 扁平 8B),為保護基類子物件語意 (賦值不影響衍生成員)。
- 加上多態:引入
vptr、虛表、建構/解構開銷。
- 多重繼承:第一基類位移 0,第二基類需位移調整 (
pv = (Vertex*)((char*)&v3d + sizeof(Point3d)))。
- 虛繼承:分為固定區 (直接存取) 與共享區 (虛基類,間接存取)。三大策略:
- 每虛基類一指標
- 虛基類表 (Microsoft)
- 虛表負索引存放位移 (Sun/Foundation)
效率與指標
- 單一/多重繼承非虛成員存取效率同非繼承。
- 虛繼承間接存取效率差。
- 成員指標值 = 實際位移 + 1 (區分空指標與第一成員)。多重繼承下第二基類成員指標需加基類大小調整。