智能合約開發

繼承

繼承讓你以擴充其他合約的方式來建構一個合約,混入共用行為而非重寫它。多數真實合約都會繼承久經考驗的基底合約——用於存取控制的 Ownable、用於緊急停止的 Pausable、用於代幣機制的 ERC20——再於其上只加入自己的邏輯。你用 is 關鍵字宣告它:contract Token is ERC20, Ownable。

Solidity 支援多重繼承,並以 C3 線性化(與 Python 使用的演算法相同)來解決由此產生的歧義。從你列出的基底,編譯器算出一個單一的線性順序(方法解析順序,MRO),由最衍生的合約往下排到最基底的。你打算覆寫的函數,必須在基底標記 virtual、在子代標記 override。關鍵在於 super.f() 並非呼叫直接的父代——它呼叫線性化中的下一個合約,這正是混入(mixin)能可預測地串接其行為的方式。

實務上重要的細節:建構子由最基底的合約往上執行到最衍生的,與你撰寫的順序無關;基底建構子的引數可在繼承列表或衍生建構子的標頭中提供。狀態變數的儲存佈局也遵循線性化順序,這就是為何可升級合約對更動其繼承關係如此敏感。經典的鑽石問題(通往共同祖先有兩條路徑)由 C3 處理,使共同基底恰好只出現一次——但你必須由最基底到最衍生列出基底,否則編譯器會以線性化錯誤拒絕該合約。

contract A { function foo() public virtual {} }
contract B is A { function foo() public virtual override {} }
contract C is A, B {            // linearization: C, B, A
  function foo() public override(A, B) { super.foo(); }
}

C3 線性化讓多重繼承不再有歧義。

super 不是「我的父代」——在多重繼承中它是「C3 順序中的下一個合約」。兩個函數都可呼叫 super.f(),並恰好串過每個基底一次。