class Animal { public: void Op() { cout << "Animal"; } };
class Tiger : public Animal { public: void Tg() { cout << "Tiger"; } };
class Lion : public Animal { public: void Lo() { cout << "Lion"; } };
class Liger : public Tiger, public Lion { public: void Lo() { cout << "Liger"; } };
int main() {
Liger lg;
lg.Op(); // ❌ 編譯錯誤:request for member 'Op' is ambiguous
}
原因:Liger 含兩份 Animal 子物件(分別來自 Tiger、Lion),呼叫 Op() 時編譯器不知選哪份。
Liger 物件佈局 (低址→高址): 1. Animal (Tiger 路徑) 成員 2. Tiger 成員 (含 Op) 3. Animal (Lion 路徑) 成員 ← 第二份 Animal 4. Lion 成員 (含 Op) 5. Liger 自身成員
class Tiger : public virtual Animal { ... };
class Lion : public virtual Animal { ... };
Liger 物件佈局 (低址→高址): 1. Animal 成員 (共享單一份) ← 由最衍生類 Liger 決定位置 2. Tiger 成員 (不含 Animal 部分) 3. Lion 成員 (不含 Animal 部分) 4. Liger 自身成員
關鍵:虛基類子物件由最衍生類決定位置並共享唯一份,消除歧義。
vptr 指向虛表 (函數指針陣列)vbptr (虛基類表指針) 或在虛表中增加偏移量項,用於運行期定位共享虛基類位置lg.Op() → Animal::Op(&lg),this 指針隱式傳遞Q: 虛繼承下,
sizeof(Liger)比普通繼承大還是小?
A: 通常較大。雖省去一份Animal,但引入vbptr/虛表偏移量,且對齊填充可能增加。