Solidity 合约继承

Solidity 语言提供了继承的支持,实现的方式是通过复制包括多态的代码到子类来实现的。Solidity 语言的合约继承通过关键字 is 来实现。

由于 Solidity 继承的实现方案是代码拷贝,所以合约继承后,部署到网络时,将变成一个合约,代码将从父类拷贝到子类中。

 

1. 继承示例

继承通过关键字 is 来实现,例如:

pragma solidity ^0.8.0;
contract Person{
  string name;
  uint age;
}
contract Man is Person{
}

 

2. 子类访问父类权限

子类访问父类权限修饰符包括:public、internal、private,例如:

pragma solidity ^0.8.0;
contract A{
  uint stateVar;

  function somePublicFun() public{}
  function someInternalFun() internal{}
  function somePrivateFun() private{}
}

contract B is A{
  function call(){
    //访问父类的`public`方法
    somePublicFun();

    //访问父类的状态变量(状态变量默认是internal权限)
    stateVar = 10;

    //访问父类的`internal`方法
    someInternalFun();

    //不能访问`private`
    //somePrivateFun();
  }
}

 

3. 传参数到父类

子类传参数到父类有两种方式:

(1). 直接传递

pragma solidity ^0.8.0;
contract Base{
  uint a;

  function Base(uint _a){
    a = _a;
  }
}

contract Test is Base(1){
  function getBasePara() returns(uint){
    return a;
  }
}

(2). 根据输入值传递

pragma solidity ^0.8.0;
contract Base{
  uint a;
  function Base(uint _a){
    a = _a;
  }
}
contract T is Base{
  function T(uint _a) Base(_a * _a){}

  function getBasePara() returns (uint){
    return a;
  }
}

 

4. 多重继承中的重名

多重继承中不允许出现相同的函数名、事件名、修改器名以及状态变量名等。

示例以下:

pragma solidity ^0.8.0;

contract Employee1 {
    function getSalary() public pure returns(int){
        return 1;
    }
}

contract Employee2 {
    function getSalary() public pure returns(int){
        return 1;
    }
}

contract Manager is Employee1,Employee2 {
}

由于基类 Employee1、Employee2 中同时包含函数 getSalary,构成重名,所以以上代码会出现编译错误。

pragma solidity ^0.8.0;

contract Employee {
    function getSalary() public  pure returns(int){
        return 1;
    }
}

contract Manager is Employee {
    function getSalary() public  pure returns(int){
        return 2;
    }
}

由于基类 Employee 和 父类 Manager 中同时包含函数 getSalary,构成重名,所以以上代码会出现编译错误。

还有一种比较隐蔽的情况,默认状态变量的getter函数导致的重名。

示例以下:

pragma solidity ^0.8.0;

contract Employee1 {
  uint public data = 10;
}

contract Employee2 {
  function data() returns(uint){
    return 1;
  }
}
contract Manager is Employee1, Employee2{}

由于 Employee1 的状态变量 data,会默认生成 getter,函数名为 data(),于是 Employee1 和 Employee2 函数重名出错。

 

5. 重写函数

从 0.6 开始,solidity 引入了 abstract, virtual, override 几个关键字,用于重写函数。

示例以下:

pragma solidity ^0.8.0;

contract Employee {
    function getSalary() public  pure virtual returns(int){
        return 1;
    }
}

contract Manager is Employee {
    function getSalary() public  pure override returns(int){
        return 2;
    }
}

调用 Manager 的 getSalary 函数,将会得到结果 2。

基类中可以包含没有实现代码的函数,也就是纯虚函数,那么基类必须声明为 abstract。

示例以下:

pragma solidity ^0.8.0;

abstract contract Employee {
    function getSalary() public  pure virtual returns(int);
}

contract Manager is Employee {
    function getSalary() public  pure override returns(int){
        return 2;
    }
}

Solidity 是通过回退状态的方式来处理异常错误。发生异常时会撤消当前调用及其所有子调用所改变的状态,同时给调用者返回一个错误标识。1. 条件检查Solidity 提供了assert 和 require 来进 ...