フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

Solidity で同名の関数や変数名を継承したらどうなる?

f:id:lirlia:20220212125721p:plain

変数と関数を上書きする

  • override1 -> test
  • override2 -> test の場合

override1.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract override1 {
  string val = "";
  function setVal() external {
    val = "override1";
  }
}

override2.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract override2 {
  string val = "";
  function setVal() external {
    val = "override2";
  }
}

test1.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "./override1.sol";
import "./override2.sol";

contract test is override1, override2 {

  function getValue() external view returns(string memory) {
    return val;
  }
}

コンパイルするとすでに変数も関数も存在しているので上書きできないよと怒られてしまいました。

Compiling your contracts...
===========================
> Compiling ./contracts/override1.sol
> Compiling ./contracts/override2.sol
> Compiling ./contracts/test.sol

DeclarationError: Identifier already declared.
 --> project:/contracts/override1.sol:5:3:
  |
5 |   string val = "";
  |   ^^^^^^^^^^^^^^^
Note: The previous declaration is here:
 --> project:/contracts/override2.sol:5:3:
  |
5 |   string val = "";
  |   ^^^^^^^^^^^^^^^

,TypeError: Derived contract must override function "setVal". Two or more base classes define function with same name and parameter types.
 --> project:/contracts/test.sol:7:1:
  |
7 | contract test is override1, override2 {
  | ^ (Relevant source part starts here and spans across multiple lines).
Note: Definition in "override1": 
 --> project:/contracts/override1.sol:6:3:
  |
6 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).
Note: Definition in "override2": 
 --> project:/contracts/override2.sol:6:3:
  |
6 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).

変数と関数を上書きする(多重継承)

  • override3 -> override4 -> test の場合

override3.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract override3 {
  string val = "";
  function setVal() external {
    val = "override3";
  }
}

override2.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "./override3.sol";

contract override4 is override3 {
  string val = "";
  function setVal() external {
    val = "override4";
  }
}

test2.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "./override4.sol";

contract test is override4 {

  function getValue() external view returns(string memory) {
    return val;
  }
}

同じくコンパイルエラーで怒られてしまいました。

Compiling your contracts...
===========================
> Compiling ./contracts/override3.sol
> Compiling ./contracts/override4.sol
> Compiling ./contracts/test2.sol

DeclarationError: Identifier already declared.
 --> project:/contracts/override4.sol:7:3:
  |
7 |   string val = "";
  |   ^^^^^^^^^^^^^^^
Note: The previous declaration is here:
 --> project:/contracts/override3.sol:5:3:
  |
5 |   string val = "";
  |   ^^^^^^^^^^^^^^^

,DeclarationError: Identifier already declared.
 --> project:/contracts/override4.sol:7:3:
  |
7 |   string val = "";
  |   ^^^^^^^^^^^^^^^
Note: The previous declaration is here:
 --> project:/contracts/override3.sol:5:3:
  |
5 |   string val = "";
  |   ^^^^^^^^^^^^^^^

,TypeError: Overriding function is missing "override" specifier.
 --> project:/contracts/override4.sol:8:3:
  |
8 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).
Note: Overridden function is here:
 --> project:/contracts/override3.sol:6:3:
  |
6 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).

,TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?
 --> project:/contracts/override3.sol:6:3:
  |
6 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).
Note: Overriding function is here:
 --> project:/contracts/override4.sol:8:3:
  |
8 |   function setVal() external {
  |   ^ (Relevant source part starts here and spans across multiple lines).

このように override3 を変えても同様のエラーで失敗します。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract override3 {
- string val = "";
+ string val = "123";
  function setVal() external {
    val = "override3";
  }
}

変数と関数を上書きする(virtual利用)

  • override5 -> override6 -> test の場合

ここで公式サイトを見ていたら virtual / override を指定することで function を override できるというジャストな方法が記載されていました!!!

override5.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract override5 {
  string val = "";
  function setVal() virtual external {
    val = "override5";
  }
}

override6.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "./override5.sol";

contract override6 is override5 {
  function setVal() external override {
    val = "override6";
  }
}

test3.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "./override6.sol";

contract test is override6 {

  function getValue() external view returns(string memory) {
    return val;
  }
}

これを実際に動かしてみたところ override6 がセットされていた。

truffle(develop)> compile
truffle(develop)> test.new().then(i => c = i)
truffle(develop)> c.getValue()
''
truffle(develop)> c.setVal()
truffle(develop)> c.getValue()
'override6'

まとめ

  • 関数や変数の override はできない
  • ただし明示的に設定をすることで関数に関しては可能になる