Solidity
在合約 D 中,為什麼呼叫函式 bar 先呼叫 C,然後呼叫 B,最後呼叫 A?
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /* Inheritance tree A / \ B C \ / D */ contract A { // This is called an event. You can emit events from your function // and they are logged into the transaction log. // In our case, this will be useful for tracing function calls. event Log(string message); function foo() public virtual { emit Log("A.foo called"); } function bar() public virtual { emit Log("A.bar called"); } } contract B is A { function foo() public virtual override { emit Log("B.foo called"); A.foo(); } function bar() public virtual override { emit Log("B.bar called"); super.bar(); } } contract C is A { function foo() public virtual override { emit Log("C.foo called"); A.foo(); } function bar() public virtual override { emit Log("C.bar called"); super.bar(); } } contract D is B, C { // Try: // - Call D.foo and check the transaction logs. // Although D inherits A, B and C, it only called C and then A. // - Call D.bar and check the transaction logs // D called C, then B, and finally A. // Although super was called twice (by B and C) it only called A once. function foo() public override(B, C) { super.foo(); } function bar() public override(B, C) { super.bar(); } }
據我了解,呼叫 D.bar() 首先執行 C.bar (直接父級),然後呼叫 A.bar (契約 Cs 父級)。誰能解釋為什麼在這裡呼叫契約 B?
請不要誤以為 Solidity 是一種物件導向的語言;它不是。
層次結構只是一種告訴編譯器將函式放在最終智能合約中的位置的方法。它有自己的解析邏輯,所以如果事情變得太奇怪了,乾脆把它去掉。
引入層次結構功能以簡化開發。如果它造成混亂,就像在這種情況下,最好避免它。
實際上,當您編譯上述合約時,會發生所有程式碼和功能合併到一個合約中的情況。
在合併程式碼時,如果編譯器發現一個具有相同簽名(名稱+參數類型)的函式,它會覆蓋前一個函式,只保留最後一個。
順序由
is
關鍵字決定:contract D is B, C
表示 的函式B
在 的函式之前合併C
。在這種情況下
C.foo()
勝過,B.foo()
並且B.foo()
實際上並不存在於最終契約中。這就是流量的原因D.foo() -> C.foo() -> A.foo()
。相反,如果您指定
super
關鍵字,Solidity 編譯器會理解您希望在最終合約中保留相應父級的函式,然後將這些函式按其讀取的相反順序放置D.bar() -> C.bar() -> B.bar() -> A.bar()
另外,請注意
儘管 super 被呼叫了兩次(被 B 和 C 呼叫),但它只被呼叫了一次 A。