多重繼承是物件導向語言設計中極具爭議的特性。Eiffel 與 C++ 直接支援,Java 則以介面機制替代。本文深入剖析多重繼承的核心難題、各語言的解決策略與工程權衡。
Sun 主張多重繼承帶來諸多問題,C++ 的實作方式更印證此點。看似簡化設計的理由(如混入 utility 函數)經證明意義有限。核心難題清單極長:
Java 介面僅允許抽象方法與常數欄位,消除了實作衝突選擇的必要。常數欄位在多重實作時自動合併,但若常數值不一致將導致編譯錯誤。雖失去混入非抽象實作的能力,但可透過組合模式達到同等效果,不構成嚴重缺失。
Eiffel 未引入單獨介面機制,而是在繼承子句中完整解決:
renaming:重新命名衝突特徵確保唯一性redefining/undefining:調整匯出策略select:顯式消除歧義C++ 採用域解析運算子 :: 於使用點消除歧義。缺點顯著:
::,降低可讀性與擴充性ANSI 委員會曾考慮引入 renaming 但被否決,專家尚需兩週評估,可見複雜度。Stroustrup 著作中展示的替代方案同樣晦澀。
(A,B) ≠ (B,A)Eiffel 允許 class B inherit A, A end,C++ 則禁止 class B : public A, public A。這反映了兩語言對型別系統純度與實作複雜度的不同取捨。
多重繼承相關問題可系統性識別並優雅解決(Eiffel 證明)。但 C++ 的實作機制導致高認知負擔與維護成本。現代設計傾向:優先使用組合、介面隔離、策略模式,僅在極少數領域模型強制要求時謹慎使用多重繼承,並嚴格遵循「介面繼承為主、實作繼承為輔」原則。