例子1:多继承下有重名函数,执行哪个函数的问题
contract owned {
funtion owned() { owner =msg.sender;} //构造函数
address owner;
}
contract mortal is owned { //mortal继承自owned
function kill() {
if(msg.sender==owner) selfdestruct(owned);
}
}
contract Base1 is mortal {
function kill() { /* do clean up 1*/ super.kill();}
}
contract Base2 is mortal {
function kill() { /* do clean up 2*/ super.kill();}
}
contract Final is Base1,Base2{
}
- Base1和Base2是mortal的派生合约
- Final是Base2和Base1的派生合约
- Final派生自两个合约(Base2和Base1),这两个父合约的顺序是有意义的,继承时会按照从左到右的顺序依次继承重写。
- 合约中的函数都是虚函数,这意味着除非指定类名,否则调用的都是最后派生的函数。
- 在例子中,Final先继承Base2,然后继承Base1,此时Base2中的kill函数将被Base1中的kill函数重写。
- 所以,Final的继承序列为Final、Base2、Base1、mortal、owned
- 当调用Final实例的kill函数时,将依次调用:Base2.kill()、Base1.kill()、mortal.kill()
- 若Base1和Base2中的super.kill()换成mortal.kill(),则调用顺序为Base2.kill()、mortal.kill()
测试如下:
(1)Base1和Base2中的super.kill()换成mortal.kill(),外部调用Final的kill方法,会跳过Base1的kill,只执行Base2的kill,最终执行mortal中的kill方法
pragma solidity ^0.4.0;
contract owned {
function owned() { owner = msg.sender; }
address owner;
}
contract mortal is owned {
event mortalCalled(string);
function kill() {
mortalCalled("mortalCalled");
if (msg.sender == owner) selfdestruct(owner);
}
}
contract Base1 is mortal {
event base1called(string);
function kill() { /* do cleanup 1 */base1called("do cleanup 1"); mortal.kill(); }
}
contract Base2 is mortal {
event base2called(string);
function kill() { /* do cleanup 2 */base2called("do cleanup 2"); mortal.kill(); }
}
contract Final is Base1, Base2 { //外部调用Final的kill方法,会跳过Base1的kill,只执行Base2的kill
}
测试步骤:部署Final合约,触发kill方法,可以看到返回的日志如下,并没有触发Base1的事件
(2)Base1和Base2中都用super.kill(),则会依次调用Base2、Base1、mortal中的kill方法
pragma solidity ^0.4.0;
contract owned {
function owned() { owner = msg.sender; }
address owner;
}
contract mortal is owned {
event mortalCalled(string);
function kill() {
mortalCalled("mortalCalled");
if (msg.sender == owner) selfdestruct(owner);
}
}
contract Base1 is mortal {
event base1called(string);
function kill() { /* do cleanup 1 */base1called("do cleanup 1"); super.kill(); }
}
contract Base2 is mortal {
event base2called(string);
function kill() { /* do cleanup 2 */base2called("do cleanup 2"); super.kill(); }
}
contract Final is Base1, Base2 { //外部调用Final的kill方法,会依次调用Base2、Base1、mortal中的kill方法
}
例子2:(继承合约参数)
contract Base{
uint x;
function Base(uint _x) {x=_x;}
}
contract Derived is Base(7) {
function Derived(uint _y) Base(_y *_y) {
}
}
- 派生合约的构造函数需要提供基类合约构造函数的所有参数,有两种方法
- 第一种是上面 在继承列表中指定 is Base(7)
- 另一种是在定义派生类的构造函数时,提供 Base (_y *_y),当基本合约(基类)的构造函数参数为变量时,应当用这种方式。
- 当两种方式同时存在时,以第二种方式为准。
例子3:重写(抽象合约)
contract Feline{
function utterance() returns (bytes32); //抽象合约
}
contract Cat is Feline{
function utterance() returns (bytes32) {return "miaow";}
}
- Solidity允许使用抽象合约。
- 抽象合约是指一个合约只有函数声明而没有函数的具体实现,即函数的声明以“;”结束
- 只要合约中有一个函数没有具体的实现,即使合约中其他函数已实现,这一抽象合约就不能被编译。
另外,在子类中允许重写函数,但不允许重写返回参数
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){} 这一个重写了返回参数,会报错。
关于访问父类变量:
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的。
继承不允许重名
即父类和子类的修改器,方法,事件等不可以有相同的名字【不过在remix测试下并没有这个问题】,还有就是隐蔽的重名方式(getter访问器)见下面
pragma solidity ^0.4.0;
contract Base1{
uint public data = 10;
}
contract Base2{
function data() returns(uint){
return 1;
}
}
//一种隐蔽的情况,默认getter与函数名重名了也不行
转载自:http://me.tryblockchain.org/blockchain-solidity-inheritance.html