1.可以通过override重写父合约virtual函数

  1. pragma solidity ^0.8.0;
  2. contract Base1{
  3. function data() virtual public pure returns(uint) {
  4. return 1;
  5. }
  6. }
  7. contract Base2{
  8. function data() virtual public pure returns(uint) {
  9. return 2;
  10. }
  11. }
  12. contract MostDerived1 is Base1, Base2{
  13. // 必须重载data()函数因为Base1 和 Base2都有data函数
  14. function data() public override(Base1,Base2) pure returns(uint){
  15. return 3;
  16. }
  17. // 返回1
  18. function call1() public pure returns(uint){
  19. return Base1.data();
  20. }
  21. // 返回2
  22. function call2() public pure returns(uint){
  23. return Base2.data();
  24. }
  25. // 返回3
  26. function call3() public pure returns(uint){
  27. return data();
  28. }
  29. }

2.继承链中不能有相同的变量名

pragma solidity ^0.8.0;

contract Base1{
    uint256 public data1 ;
    function data() virtual public {
        data1 = 1;
    }
}

contract Base2{
    uint256 public data1 ;
    function data() virtual public {
        data1 = 2;
    }
}

contract MostDerived1  is Base1 , Base2{

    function data() virtual override public {

    }

}

编译会报错:
截屏2022-01-07 下午9.29.20.png

3.重写遵循最远继承原则

通过super调用只会执行一个

pragma solidity ^0.8.0;

contract Base1{
    uint256 public data1 ;
    function data() virtual public {
        data1 = 1;
    }
}

contract Base2{
    uint256 public data2 ;
    function data() virtual public {
        data2 = 2;
    }
}

contract MostDerived1  is Base1 , Base2{
    // 只会执行Base2.data
  /*
  在继承链中,由于继承实现是代码复制。如果出现函数名重写,最终使用的是继承链上哪个合约定义的代码呢?实际执行时,依据的是最远继承的原则(most derived),即使用最后出现的Base2.data()
  */
    function data() virtual override(Base1 , Base2) public {
        super.data();
    }

      // Base1.data 和 Base2.data都会执行
      function data() virtual override(Base1 , Base2) public {
        Base1.data();
        Base2.data();
    }

    function data() virtual override(Base1 , Base2) public {
        Base1.data();
        super.data();
    }

}

4.使用super 会依照最远继承链的形式依次执行继承链中的函数

pragma solidity ^0.8.0;

contract owned {
    address public owner;
    constructor() { owner = msg.sender; }

}

contract mortal is owned {
    event mortalCalled(string);
    function kill() public virtual  {
       emit mortalCalled("mortalCalled");
        if (msg.sender == owner){
            owner = address(0x1);
        }
    }
}


contract Base1 is mortal {
    event Base1Called(string);
    function kill() public virtual override  {
      /* do cleanup 1 */
      emit Base1Called("Base1Called");
      super.kill();
    }
}


contract Base2 is mortal {
    event Base2Called(string);
    function kill() public virtual  override{
      /* do cleanup 2 */
      emit Base2Called("Base2Called");
      super.kill();
    }
}


contract FinalWithSuper is Base1, Base2 {

    function kill() public virtual  override(Base1 , Base2){
      /* do cleanup 2 */
      emit Base2Called("FinalWithSuperCalled");
      super.kill();
    }
}

事件触发顺序:
截屏2022-01-08 上午1.43.08.png
在上面的代码中,我们调用FinalWithSuper的kill()方法,将触发按最远继承原则形成的链 Final,Base2,Base1,motal,owned的调用

5.多继承与线性化(Multiple Inheritance and Linearization)

pragma solidity ^0.8.0;

contract X {}
contract A is X {}
contract C is A, X {}

截屏2022-01-08 上午1.47.33.png
error reson:
对于C合约来说按照最远继承原则,X会重写A
对于A合约来说,A继承于X,所以A会重写X
因此造成冲突

解决:

pragma solidity ^0.8.0;

contract X {}
contract A is X {}
contract C is X, A {}

6.合约会依次执行继承合约的构造函数

pragma solidity ^0.8.0;

contract Base1{
    uint256 public data1 ;
    constructor() {
        data1 = 1;
    }
}

contract Base2{
    uint256 public data2 ;
     constructor() {
        data2 = 2;
    }
}


contract MostDerived is Base1 , Base2{

    // data1=1
      // data2=2
}

7.变量存储位置与继承顺序


pragma solidity 0.8.0;

contract storageValue1{
    uint256  public a ;
    constructor(){
        a =1;
    }
}

contract storageValue2{
    uint256  public b ;
    constructor(){
        b =2;
    }
}

contract storageVal is storageValue1 , storageValue2{
    // 1
    function getSlot0() public view  returns(uint256 res){
        assembly{
            res := sload(0)
        }
    }

      // 2
    function getSlot1() public view  returns(uint256 res){
        assembly{
            res := sload(1)
        }
    }

}

结论:按照继承顺序继承