Solidityの多重継承やダイヤモンド継承を攻略する(Solidity0.8.0対応)
こんにちはヤマピーブラックです。
ブロックチェーンゲーム会社のCryptoGamesとdouble jump.tokyoでコントラクト開発をしています。
今回はSolidityにおける多重継承、ダイヤモンド継承の書き方、挙動について解説します。
特にSolidity0.6.0以降、継承したfunctionにはoverrideを記載しなければならず、書き方もひとクセあります。そのあたりも含めて解説します。
多重継承における実行順
以下のような構成を考えます。
※console.logはhardhatを使用
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B {
function foo() virtual public {
console.log("foo B");
}
}
contract C is A, B {
function foo() override(A,B) public {
console.log("foo C");
}
}
solidity0.6.0から継承元を列挙、override(A,B)と記載する必要があります。
実行結果
foo C
当然ですがsuperをつけない場合はCが実行されて終わりです。
superあり
superつけた場合はどうなるでしょう。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B {
function foo() virtual public {
console.log("foo B");
}
}
contract C is A, B {
function foo() override(A,B) public {
console.log("foo C");
super.foo();
}
}
実行結果
foo C
foo B
contract C is A, Bの後に書いたほう、Bが後勝ちとなる形です。
contract C is B, Aと逆に書くと、Aが実行されます。(割愛します)
overrideを逆順に
ここで、contract C is A, Bのままoverride(B,A)とoverrideのところだけ逆に記載するとどうなるでしょうか。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B {
function foo() virtual public {
console.log("foo B");
}
}
contract C is A, B {
function foo() override(B,A) public {
console.log("foo C");
super.foo();
}
}
実行結果
foo C
foo B
結果は変わりませんでした。つまり、contract C is A,Bの順番が重要で、overrideに記載する順番はどうでもよいということです。
まあ、functionの順番だけ器用に変更するのは無理でしょうかね。訳わかんなくなりそうですし。
ダイヤモンド継承における実行順
続いてダイヤモンド継承を考えます。B,C,Dにsuperをつけました。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B is A {
function foo() override virtual public {
console.log("foo B");
super.foo();
}
}
contract C is A {
function foo() override virtual public {
console.log("foo C");
super.foo();
}
}
contract D is B,C {
function foo() override(B,C) public {
console.log("foo D");
super.foo();
}
}
実行結果
foo D
foo C
foo B
foo A
D→C→B→A。このような順番で実行されます。Cの親はAですが、兄弟クラスであるBが先に評価されるのが特徴です。
一部superなし
続きまして、Bのsuperを削除します。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B is A {
function foo() override virtual public {
console.log("foo B");
}
}
contract C is A {
function foo() override virtual public {
console.log("foo C");
super.foo();
}
}
contract D is B,C {
function foo() override(B,C) public {
console.log("foo D");
super.foo();
}
}
実行結果
foo D
foo C
foo B
D→C→BといってBでSTOPします。
一部function削除
さらに、Bのfoo()自体を削除してみるとどうなるでしょう。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract A {
function foo() virtual public {
console.log("foo A");
}
}
contract B is A {
}
contract C is A {
function foo() override virtual public {
console.log("foo C");
super.foo();
}
}
contract D is B,C {
function foo() override(A,C) public {
console.log("foo D");
super.foo();
}
}
実行結果
foo D
foo C
foo A
今度はAがちゃんと実行されます。また、Dはoverride(A,C)と記載しなければエラーとなります。
まとめ
・contract is A,B... 後から書いたものから実行される
・親より兄弟が先に実行される
・superがないとそこでSTOP
・兄弟のfunctionがない場合は親にいく
以上で一応理解はできましたが、hardhatでconsoleを出しながらやるのが一番かもしれませんね。
constructorの実行についてもいずれ書きたいと思います。
Author And Source
この問題について(Solidityの多重継承やダイヤモンド継承を攻略する(Solidity0.8.0対応)), 我々は、より多くの情報をここで見つけました https://qiita.com/yamapyblack/items/b6674fba2ad20efc2957著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .