物件導向(Object-Oriented Programming,OOP) 可以用來提高程式碼的可讀性、可維護性和可擴展性,同時還能夠促進程式碼的重用和組織。
以挖礦為例,當挖掘鑽石礦時,會獲得鑽石等物品。我們可以定義一個統一的礦物基類,並通過覆蓋其方法來確保挖掘特定礦物時會掉落相應的物品。這比傳統的 if-else 判斷方式更為簡潔,只需判斷挖掘的對象是否為礦物,無需關注具體的礦物類型。這樣的多型實現使程式碼更具靈活性和可擴展性。
多型與指標密切相關。通過改變指標來決定當前的礦物類型,指向不同的具體礦物類別(如鑽石礦或金礦),從而實現多型。利用 virtual 和 override 關鍵字,我們可以動態地選擇合適的函數實現。
在基類中聲明純虛擬函數,要求所有子類必須提供具體實現。這樣可以確保每個子類都有自己專屬的行為。
將衍生類別轉型為基類別是多型的一部分。我們可以利用基類別的指標操作不同類型的物件,實現通用處理。例如,一個人挖礦時,無論挖掘的是何種礦物,都會掉落相應的物品。這種方法可以省去大量的 if-else 判斷邏輯。
物件轉型可以方便地替換為我們「想要的類型」,提高程式碼的靈活性和可重用性。
如果將子類別轉型為基類別,而基類別中沒有相關的定義,則無法正常運行。
如果基類中定義了 virtual 函數,而子類中對其進行了覆蓋(override),編譯器會在運行時自動選擇合適的子類實現。
如果不使用 virtual 和 override,嘗試通過基類指標調用子類中的函數時,會出現調用基類函數的情況,導致返回不正確的結果。
在編譯時期進行綁定,將所有函數綁定在一起。
在運行時期進行綁定,允許程式在執行過程中動態綁定需要的函數定義。
使用提早綁定,直接在編譯時期綁定基類的定義。
編譯器會使用延遲綁定,在運行時期動態尋找函數的定義,從而調用子類的相關函數實現。
對於具有衍生類別的物件,解構順序是從最底層子類的解構子開始,逐步釋放到最上層基類的解構子。這樣可以確保所有資源都能正確釋放,避免內存泄漏。
以熔爐為例,減少同樣函數原型、不同類別、不同實作細節所造成的特殊判斷情況。例如,不同的礦物可以逐一燒成錠,這樣可以減少冗長的判斷邏輯。
如果有多種類型的礦物,需要為每一種礦物編寫對應的處理邏輯。
利用繼承和多型,只要繼承自礦物基類,並實現相應的燒製方法,就能大大減少重複的實現細節。
針對同名但參數不同的函數,C++ 會自動選擇對應的函數實現。例如,AddOre() 函數可以有不同的參數個數和類型,C++ 會自動匹配合適的函數。
相同名稱但參數不同的函數。函數重載與函數匹配實現了相同的功能,使得同一個操作可以對多種類型的數據進行處理。
可以重載 C++ 內建的運算符,使得物件之間可以進行相加、相減等運算。例如,玩家的移動可以通過位置(三維空間的座標 x, y, z)的相加來實現。
使用模板讓類別使用通用型別,並將類別中通用型別變成指定型別。這樣可以避免為每種礦物創建不同的類別,而是使用模板來實現通用化。
通過提早綁定,在編譯時期自動綁定傳入型別的函數。
對特定函數使用通用型別 (Generic),使得函數可以處理不同型別的數據。
根據 StackOverflow 上的專家回答,以下情況應該使用類別模板:
不需要關心物件是否真的是礦物,只要能燒就可以處理。例如,木頭可以像礦物一樣燒,只要滿足最低需求即可運行。這種方式讓程式碼更具彈性。
只要編譯能通過,無論是否符合語義,只要符合規則即可運行。
通過抽象具體型別,變成通用處理,解決程式碼冗長的問題。
減少同樣函數原型、不同類別、不同實作細節所造成的特殊判斷情況。
相同名稱但不同參數的函數。
將不同型別的部分抽象成模板,根據使用者傳入的型別進行替換。
成員內具有其他類別成員,這個類別擁有「類別成員」的所有權。建構子或 Setter 中設定這些成員。例如,不同的食材組合可以創造不同的炒飯。當物件被解構時,所有成員都會被釋放。
成員內的所有成員都會被釋放。由於物件擁有其成員,當物件被解構時,其成員也應一同被釋放。
組合可以實現類似「委派」的功能。例如,將裝備丟到附魔台中進行附魔。
組合內的成員不會全部釋放。玩家有附魔台,裝備丟進去附魔,但附魔台消失時,裝備不會消失。委派是附魔的動作,組合是將附魔台和裝備結合。
通過純虛擬函數和繼承實現「介面」,讓所有會攻擊玩家的對象都繼承一個介面,並讓子類實現細節。
描述改變某些東西時造成的影響程度。
程式碼重複度低,但繼承鏈很長。
程式碼會重複,但繼承鏈短,維護方便。
以怪物繼承為例,將重複的程式碼提到父類以提升程式碼整潔度,但容易增加耦合度。
將重複的程式碼提到父類以提升程式碼整潔度,但容易增加耦合度,導致維護困難。
不繼承 Mob,而是將 Mob 當成類別成員。初始化這些類別後,依然保有 Mob 的特性,通過組合與介面取代繼承類別。
地獄幽靈和終界龍都繼承 Mob 的成員和函數,可能導致編譯時期的重複。可以利用組合與介面解決這個問題。
在建構子中將類別作為參數,根據傳入的物件做出對應行為。例如,熔爐丟肉燒會飄香,丟礦石燒得較慢。
組合與介面解決繼承問題,扁平化繼承鏈,降低耦合度,更易於維護。