閱讀442 返回首頁    go 阿裏雲 go 技術社區[雲棲]


C++編程規範之37:公用繼承即可替換性。繼承,不是為了重用,而是為了被重用

摘要:

    知其然:公用繼承能夠使基類的指針或者實際引用指向某個派生類的對象,既不會破壞代碼的正確性,也不需要改變已有的代碼。

    還要知其所以然:不要通過公用繼承重用(基類中的已有)代碼,公用繼承是為了被(已經多態地使用了基對象的已有代碼)重用的。

    按照Liskov替換原則(LiskovSubstitution Principle),公用繼承所建模的必須總是“是一個(is-a)”關係:所有基類約定必須滿足這一點,因此如果依靠成功地滿足基類的約定,所有虛擬成員函數的改寫版本就必須不多於其基類版本,其承諾的也必須不少於其基類版本。使用指向Base的指針或者引用的代碼必須能正確工作,即使指針或者應用實際上指向的是Derived。

    繼承的誤用將破壞正確性。沒有被正確實現的繼承大多數都會無法遵守基類確定的顯式或者隱式約定而迷亂。這種約定可能是很微妙的,如果無法在代碼中直接表達,程序員就必須格外小心。

    公用繼承的目的是實現可替換性,公用繼承的目的並不是為了派生類重用積累的代碼,從而用基類代碼實現自己。這種“用……來實現”的關係可能完全沒有問題,但是應該用組合關係來建模——或者僅僅在某些特殊情況下,通過非公用繼承來實現。

    還可以用另一種說法來表述:當動態多態正確而且適合時,組合是自私的,而繼承是慷慨的。心的派生類是已有通用抽象的新特例。已有的動態代碼通過調用Base的虛擬函數來使用Base&或者Base*,應該能夠無縫地使用繼承自Base的MyNewDerivedType的對象。心的派生類型向已有代碼中添加新功能時,不需要修改已有代碼,而是可以在加入新派生對象時無縫地增加其功能。

    新的需求應該很自然地由新代碼滿足,心的需求不應該導致對已有代碼的重新改寫。

在麵向對象技術出現之前,新代碼掉喲個已有代碼就一直很容易。尤其是公用繼承使已有代碼安全無縫地調用新代碼變得更加容易了。

最後更新:2017-04-03 12:54:02

  上一篇:go 消息隊列——維基百科
  下一篇:go Oracle報錯:ORA-01033:ORACLE initialization or shutdown in process