在計算機科學中，C3 演算法主要用在多重繼承中，確定子類應該繼承哪一個父類的方法。換句話說，C3 超類線性化的輸出是確定性的方法決定次序（MRO：Method Resolution Order）。 描述 C3 演算法得名於它的實現符合三種重要性質：一致性擴充套件（EPG）、保留區域性優先次序和適合單調性準則。 在 1996 年的 OOPSLA 會議上，發表的論文《Dylan 的單調超類線性化》，首次提出了 C3 超類線性化。它在 2012 年 1 月被適配到了 Open Dylan 實現，跟從了一個增進的提議。Python 23、Raku、Parrot、Solidity 和的面嚮物件語言模組等，將它選作方法解析的預設演算法。Perl 5 語言從版本 5100 起將它作為可選的、非預設的 MRO。早期版本 Perl 5 有稱為 ClassC3 一個擴充套件實現曾釋出於 CPAN。 Python 創始人 Guido van Rossum 這樣總結 C3 超類線性化：基本上，在 C3 背後的想法是，如果你寫下在複雜的類層級中繼承關係所施加的所有次序規則，這個演算法將確定出滿足所有這些規則的這些類的一個單調次序。如果不能確定出這樣的次序，這個演算法會失敗。 演算法 一個類的 C3 超類線性化，是這個類加上它的這些父類的線性化和這些父類自身的列表的唯一性歸併的總和。這些父類的列表作為給這個歸併過程的最後實際引數，保持了這些直接父類的區域性優先次序。 完成父類的線性化和父類列表的歸併，選擇這些列表的頭部中第一個符合條件者，它不出現在任何這些列表的尾部（一個列表的除了第一個元素的所有元素）之中。注意一個良好頭部，可以同時出現為多個列表的第一個元素，但是禁止它出現在任何其他地方。將選擇的元素從以它作為頭部的所有列表中移除，並將它填加到輸出列表。重複選擇並移除良好頭部並擴充套件輸出列表的過程，直到所有餘下的列表被竭盡。如果在某一點上，因為所有餘下列表的頭部都出現在某個列表的尾部中，而沒有良好頭部可選，那麼由於在繼承層級中依賴的不一致次序，歸併過程不能計算下去，故而最初類的線性化不存在。 計算一個類的線性化的一種樸素分治法，可以採用遞迴演算法來為歸併子例程找到父類的線性化。但是，這將在出現環狀類層級時導致無限迴圈遞迴。為了檢測這種環並打破無限遞迴，並重新利用前面計算的結果作為一種最佳化，遞迴呼叫應當透過快取或記憶化的方式遮蔽重入以前的實際引數。 這個演算法類似於找到拓撲次序。 例子 給定 class O class A extends O class B extends O class C extends O class D extends O class E extends O class K1 extends A B C class K2 extends D B E class K3 extends D A class Z extends K1 K2 K3 Z 的線性化計算： L O O O 的線性化就是平凡的單例列表 O，因為 O 沒有父類 L A A merge L O O A 的線性化是 A 加上它的父類的線性化與父類列表的歸併 A merge O O A O 其結果是簡單的將 A 前置於它的單一父類的線性化 L B B O B、C、D 和 E 的線性化的計算類似於 A L C C O L D D O L E E O L K1 K1 merge L A L B L C A B C 首先找到 K1 的父類的線性化 L A、L B 和 L C，接著將它們歸併於父類列表 A B C K1 merge A O B O C O A B C 類 A 是第一個歸併步驟的良好候選者，因為它只出現為第一個和最後一個列表的頭部元素。 K1 A merge O B O C O B C 類 O 不是第二個歸併步驟的良好候選者，因為它還出現在列表 2 和列表 3 的尾部中；但是類 B 是良好候選者 K1 A B merge O O C O C 類 C 是良好候選者；類 O 仍出現在列表 3 的尾部中 K1 A B C merge O O O 最後，類 O 是有效候選者，這還竭盡了所有餘下的列表 K1 A B C O L K2 K2 merge L D L B L E D B E K2 merge D O B O E O D B E 選擇 D K2 D merge O B O E O B E 不選 O，選擇 B K2 D B merge O O E O E 不選 O，選擇 E K2 D B E merge O O O 選擇 O K2 D B E O L K3 K3 merge L D L A D A K3 merge D O A O D A 選擇 D K3 D merge O A O A 不選 O，選擇 A K3 D A merge O O 選擇 O K3 D A O L Z Z merge L K1 L K2 L K3 K1 K2 K3 Z merge K1 A B C O K2 D B E O K3 D A O K1 K2 K3 選擇 K1 Z K1 merge A B C O K2 D B E O K3 D A O K2 K3 不選 A，選擇 K2 Z K1 K2 merge A B C O D B E O K3 D A O K3 不選 A，不選 D，選擇 K3 Z K1 K2 K3 merge A B C O D B E O D A O 不選 A，選擇 D Z K1 K2 K3 D merge A B C O B E O A O 選擇 A Z K1 K2 K3 D A merge B C O B E O O 選擇 B Z K1 K2 K3 D A B merge C O E O O 選擇 C Z K1 K2 K3 D A B C merge O E O O 不選 O，選擇 E Z K1 K2 K3 D A B C E merge O O O 選擇 O Z K1 K2 K3 D A B C E O 完成 用 Python3 展示例子 首先，定義一個元類來允許物件透過名字簡明表示： class Type type def __repr__cls return cls__name__ class O object metaclassType pass 類 O 透過名字表示自身，而不採用預設表示形式： O O class X pass X class __main__X 下面定義一些基礎類： class A O pass class B O pass class C O pass class D O pass class E O pass 接著構造這個繼承樹： class K1 A B C pass class K2 D B E pass class K3 D A pass class Z K1 K2 K3 pass 然後就可看到結果： Z__mro__ Z K1 K2 K3 D A B C E O class object 用 Raku 展示例子 Raku 預設的對類使用 C3 線性化： class A class B class C class D class E class K1 is A is B is C class K2 is D is B is E class K3 is D is A class Z is K1 is K2 is K3 say Zmro OUTPUT Z K1 K2 K3 D A B C E Any Mu Any 和 Mu 是所有 Raku 物件從其繼承的型別。 參考文獻 Category 面向物件的程式設計 Category 程式語言翻譯