Java 捨棄多重繼承,改用介面;C++ 保留並透過域解析 :: 消除歧義;Eiffel 提供重命名、選擇、未定義機制優雅解決。三種語言反映不同設計哲學:
// C++ 菱形繼承狀態重複問題
class Base { int x; };
class Derived1 : public Base { };
class Derived2 : public Base { };
class Final : public Derived1, public Derived2 { }; // 兩份 Base::x
// 解決:虛擬繼承
class Derived1 : virtual public Base { };
class Derived2 : virtual public Base { };
// Final 只有一份 Base 子物件
虛擬繼承引入指標間接層,增加物件大小與存取開銷,但消除狀態重複。
| 特性 | C++ 純虛類別 (介面模擬) | Java interface | C++/CLI interface class |
|---|---|---|---|
| 可包含資料成員 | 是 (但不建議) | 否 (僅常數) | 否 |
| 可包含預設實作 | 是 (C++20 以前無,C++20 允許) | Java 8+ default method | 否 |
| 多重實作繼承 | 支援 (含狀態) | 不支援 | 不支援 |
| 菱形問題 | 需虛擬繼承解決 | 不存在 (無狀態) | 不存在 |
Mixin 將獨立功能「混入」類別。C++ 可用多重繼承實現,但組合 + 委派更安全:
// 組合版 Mixin
class Serializable { public: virtual string serialize() = 0; };
class Loggable { public: virtual void log(const string&) = 0; };
class MyClass : public Serializable, public Loggable { // 繼承版
// ...
};
// 組合版 (推薦)
class MyClass {
unique_ptr serializer;
unique_ptr logger;
public:
string serialize() { return serializer->serialize(); }
void log(const string& msg) { logger->log(msg); }
};
組合版無菱形問題、無名稱衝突、可執行期替換實作、符合「組合優於繼承」原則。
「繼承是強關係,慎用。介面定義契約,無狀態。組合提供彈性,預設首選。語言應讓正確的事容易,錯誤的事困難。」