Solidity的继承(二十五)|入门系列

2017/6/11 posted in  Solidity入门系列

Solidity语言为我们提供了继承的支持1,实现的方式是通过复制包括多态的代码到子类来实现的。

继承

继承通过关键字is来实现,一起来看看下面的例子:

pragma solidity ^0.4.0;

contract Person{
  string name;
  uint age;
}

contract Manager is Person{
}

上面的例子中,合约Manager继承了Person合约。

继承的合约Manager可以访问所有的非私有成员。包括internal的函数和状态变量(这些是不能通过external的方式访问的,如this.yourFunc()),可见性控制详见: http://me.tryblockchain.org/solidity-function-advanced1.html 。我们来看下面的例子:

pragma solidity ^0.4.0;

contract A{
  uint stateVar;

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

contract AccessBaseContract is A{
  function call(){

    //访问父类的`public`方法
    somePublicFun();

    //访问父类的状态变量
    stateVar = 10;

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

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

从上面的例子中,我们可以看到,子类可以访问父类的publicinternal权限控制变量或函数,不能访问private权限控制的变量和函数。在子类中可以直接访问状态变量,原因是因为状态变量默认是internal的。

继承支持传参

继承时可以有两种方式传参数到父类。下面来看第一种方式:

pragma solidity ^0.4.0;

contract Base{
  uint a;

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

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

另外一种方式是类似修改器的语法,来直接看一个例子:

pragma solidity ^0.4.0;

contract Base{
  uint a;
  function Base(uint _a){
    a = _a;
  }
}
contract InheritParaModifier is Base{
  function InheritParaModifier(uint _a) Base(_a * _a){}
    
  function getBasePara() returns (uint){
    return a;
  }
}

如果要传入到基类的是简单的常量,第一种方式会更加简洁。但如果传入的参数与子类的输入参数有关,那么你应该使用第二种方式,以获取参数值。如果你同时使用了这两种方式,后一种方式将最终生效。

继承中的重名

继承中不允许出现相同的函数名,事件名,修改器名,或互相重名。

pragma solidity ^0.4.0;

contract Base1{
  address owner;
  modifier ownd(){
    if(msg.sender == owner) _;
  }

  event dupEvent(address, bytes);

  function dupFunc(){
    dupEvent(msg.sender, msg.data);
  }
}

contract Base2{
  address owner;
  modifier ownd(){
    if(msg.sender == owner) _;
  }

  event dupEvent(address, bytes);

  function dupFunc(){
    dupEvent(msg.sender, msg.data);
  }
}
//失败,将会报错 Identifier already declared
//contract DuplicateNames is Base1, Base2{}
  contract DuplicateNames is Base1{}

由于Base1Base2拥有同样的修改器,方法,事件。如果同时继承将会报错。

还有一种比较隐蔽的情况,默认状态变量的getter函数导致的重名,下面来看一个例子:

pragma solidity ^0.4.0;

contract Base1{
  uint public data = 10;
}

contract Base2{
  function data() returns(uint){
    return 1;
  }
}

//一种隐蔽的情况,默认getter与函数名重名了也不行
//contract GetterOverride is Base1, Base2{}
contract GetterOverride is Base1{}

上面的例子中,Base1中的data由于生成了默认的getter函数data(),继承中也需要注意不能重名。getter函数说明详见:http://me.tryblockchain.org/solidity-getter.html

重写函数

在子类中允许重写函数,但不允许重写返回参数签名,一起来看看下面的代码:

pragma solidity ^0.4.0;

contract Base{
  function data() returns(uint){
    return 1;
  }
}

contract InheritOverride is Base{
  function data(uint){}
  function data() returns(uint){}
  //Override changes extended function signature
  //function data() returns(string){}
}

上面代码中的function data() returns(string){}将导致Override changes extended function signature报错,因为不能修改返回签名。

其它

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

关于作者

专注基于以太坊(Ethereum)的相关区块链(Blockchain)技术,了解以太坊,Solidity,Truffle,web3.js。

个人博客: http://tryblockchain.org
版权所有,转载注明出处

参考资料

处于某些特定的环境下,可以看到评论框,欢迎留言交流^_^。

友情链接: 区块链技术中文社区    深入浅出区块链