本文主要讲解下Solidity的继承系统,主要内容为
单继承以及
多重继承。如果有其他编程经验的话,便知道继承的主要目的在于优化重复代码,是面向对象编程思想的体现。
原理
solidity通过复制包括多态的代码来支持多重继承,即当一个合约从多个合约继承时,在区块链上只有一个合约被创建,所有基类合约的代码被复制到创建的合约中。
所有的函数调用都是虚拟的,这意味着最远的派生函数会被调用,除非明确给出合约名称。派生的合约需要提供所有父合约需要的所有参数。
单继承
pragma solidity ^0.4.0;
contract Base {
uint _x;
function Base(uint x) {
_x = x;
}
}
contract Derived is Base(7) {
function Derived(uint y) Base(y * y) {
}
}
派生合约需要提供基类构造函数需要的所有参数,可以采用两种方式来实例化。 1、使用 is Base(7) 携带默认参数方式 2、派生类指定基类构造参数时,在派生类的构造函数定义Base(y * y) 的方式
优先使用第二种方式,灵活指定参数。
多重继承
同名修饰器或函数、事件
在多重继承中,基类合约的次序是非常重要的,当一个合约从多个其他合约那里继承,在区块链上仅会创建一个合约,通过复制父合约里的代码来形成继承合约。当继承最终导致一个合约同时存在多个相同名字的修饰器或函数,那将会提示错误。当事件和修饰器同名,或者函数和事件同名时,同样会被认为是一个错误。
菱形继承问题
多重继承在很多编程语言里,要解决的一个问题是,菱形继承问题,又称钻石问题 对于基类在 is 后面的顺序很重要。 在下面的代码中,Solidity 会给出“ Linearization of inheritance graph impossible ”这样的错误。
pragma solidity ^0.4.0;
contract X {}
contract A is X {}
contract C is A, X {}
代码编译出错的原因是 C 要求 X 重写 A (因为定义的顺序是 A, X ), 但是 A 本身要求重写 X,无法解决这种冲突。
多重继承的函数调用
pragma solidity ^0.4.0;
contract owned {
function owned() public { owner = msg.sender; }
address owner;
}
contract mortal is owned {
function kill() public {
if (msg.sender == owner) selfdestruct(owner);
}
}
contract Base1 is mortal {
function kill() public { super.kill(); }
}
contract Base2 is mortal {
function kill() public { super.kill(); }
}
contract Final is Base1, Base2 {
}
以上的继承序列是:Final, Base2, Base1, mortal, ownerd。
Base1和Base2 都继承mortal,如果Base1和Base2的kill函数不添加super 关键字时,调用Final.kill()只会调用Base2.kill(),而不知道Base1的kill函数。当加入super关键字时,base2会再调用继承序列里的下一个base1里的kill,这样便不会漏过业务逻辑的执行。
抽象合约
抽象合约的函数可以缺少实现,用于描述合约,并用于继承
pragma solidity ^0.4.0;
contract Feline {
function utterance() public returns (bytes32);
}
如果合约继承自抽象合约,并且没有通过重写来实现所有未实现的函数,那么它本身就是抽象的。
pragma solidity ^0.4.0;
contract Feline {
function utterance() public returns (bytes32);
}
contract Cat is Feline {
function utterance() public returns (bytes32) { return "miaow"; }
}
接口
接口类似于抽象合约,但是它们不能实现任何函数。还有进一步的限制:
- 无法继承其他合约或接口。
- 无法定义构造函数。
- 无法定义变量。
- 无法定义结构体
- 无法定义枚举。
接口基本上仅限于合约 ABI 可以表示的内容,并且 ABI 和接口之间的转换应该不会丢失任何信息。
接口interface 关键字表示:
pragma solidity ^0.4.11;
interface Token {
function transfer(address recipient, uint amount) public;
}
就像继承其他合约一样,合约可以继承接口。
|