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();
}
}
从上面的例子中,我们可以看到,子类可以访问父类的public
,internal
权限控制变量或函数,不能访问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{}
由于Base1
,Base2
拥有同样的修改器,方法,事件。如果同时继承将会报错。
还有一种比较隐蔽的情况,默认状态变量的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
版权所有,转载注明出处
参考资料
处于某些特定的环境下,可以看到评论框,欢迎留言交流^_^。