Posted at

Solidityのダイヤモンド継承の解決

More than 1 year has passed since last update.


はじめに

Solidityは多重継承がサポートされています。当然、ダイヤモンド継承問題も発生します。今まではC#をはじめとした単一継承の言語しか扱ってこなかったので、備忘録がてら多重継承した際の動作をメモしておきます。なお、本記事はethereumやsolidity、継承の仕組みについては知っていることを前提にしているので、関連事項の説明は割愛します。


多重継承の解決


Sample1.sol

pragma solidity ^0.4.11;

contract Parent {
event Log(string);

function foo() public returns (string) {
emit Log("Parent");
}
}

contract Child1 is Parent {
function foo() public returns (string) {
emit Log("Child1");
Parent.foo();
}
}

contract Child2 is Parent {
function foo() public returns (string) {
emit Log("Child2");
Parent.foo();
}
}

contract GrandSon is Child1, Child2 {}


Solidityは、isキーワードを使用して継承を行います。上記のサンプルコードでは、Parentコントラクトを基底として、Child1Child2の2つの派生コントラクトを作成しています。さらに、その2つを多重継承したGrandSonコントラクトがあります。注目していただきたいには、Parentで定義されているfooメソッドはChild1Child2の両方でオーバーライドされている点です。

この状態でGrandSonfooメソッドを呼び出すと、実行されるのはChild2Parentfooメソッドだけです。つまり、child1fooメソッドは実行されません。これは、GrandSonが基本的にはChild1を知らないからです。GrandSonからChild1Child2両方のfoo`メソッドを呼び出すためには、以下のように書き換えます。


Sample2.sol

pragma solidity ^0.4.11;

contract Parent {
event Log(string);

function foo() public returns (string) {
emit Log("Parent");
}
}

contract Child1 is Parent {
function foo() public returns (string) {
emit Log("Child1");
super.foo(); // superキーワード
}
}

contract Child2 is Parent {
function foo() public returns (string) {
emit Log("Child2");
super.foo(); // superキーワード
}
}

contract GrandSon is Child1, Child2 {}


先ほどのコードと異なり、Child1Child2内でParentfooメソッドの呼び出しにsuperキーワードが使っています。superキーワードは、基底クラスを呼び出すためのキーワードです。それだけでなく、GrandSonコントラクトが継承している次の基底コントラクトも探索します。つまり、Child1fooメソッドも実行されます。GrandSonfooメソッドを呼び出すと、最終的にはChild1Child2Parentfooメソッドが呼び出されます。


まとめ

Solidityでダイヤモンド継承を行うと、最後に継承したコントラクトだけを辿って実行します。すべての継承ルートを辿りたい場合には、superキーワードを使って基底クラスのメソッドを呼び出す必要があります。