我最近在重新学solidity,巩固一下细节,也写一个“Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。
欢迎关注我的推特:@0xAA_Science
WTF技术社群discord,内有加微信群方法:链接
所有代码和教程开源在github(1024个star发课程认证,2048个star发社群NFT): github.com/AmazingAng/WTFSolidity
这一讲,我们介绍solidity中的继承(inheritance
),包括简单继承,多重继承,以及修饰器(modifier
)和构造函数(constructor
)的继承。
继承是面向对象编程很重要的组成部分,可以显著减少重复代码。如果把合约看作是对象的话,solidity也是面向对象的编程,也支持继承。
virtual
: 父合约中的函数,如果希望子合约重写,需要加上virtual
关键字。
override
:子合约重写了父合约中的函数,需要加上override
关键。
我们先写一个简单的爷爷合约Yeye
,里面包含1个Log
事件和3个function
: hip()
, pop()
, yeye()
,输出都是”Yeye”
。
contract Yeye {
event Log(string msg);
// 定义3个function: hip(), pop(), man(),Log值为Yeye。
function hip() public virtual{
emit Log("Yeye");
}
function pop() public virtual{
emit Log("Yeye");
}
function yeye() public virtual {
emit Log("Yeye");
}
}
我们再定义一个爸爸合约Baba
,让他继承Yeye合约
,语法就是contract Baba is Yeye
,非常直观。在Baba合约里,我们重写一下hip()
和pop()
这两个函数,加上override
关键字,并将他们的输出改为”Baba”
;并且加一个新的函数baba
,输出也是”Baba”
。
contract Baba is Yeye{
// 继承两个function: hip()和pop(),输出改为Baba。
function hip() public virtual override{
emit Log("Baba");
}
function pop() public virtual override{
emit Log("Baba");
}
function baba() public virtual{
emit Log("Baba");
}
}
我们部署合约,可以看到Baba合约里有4个函数,其中hip()
和pop()
的输出被成功改写成”Baba”
,而继承来的yeye()
的输出仍然是”Yeye”
。
solidity的合约可以继承多个合约。规则:
Erzi
合约,继承Yeye合约和Baba合约,那么就要写成contract Erzi is Yeye, Baba
,而不能写成contract Erzi is Baba, Yeye
,不然就会报错。hip()
和pop()
,在子合约里必须重写,不然会报错。override(Yeye, Baba)
。例子:
contract Erzi is Yeye, Baba{
// 继承两个function: hip()和pop(),输出值为Erzi。
function hip() public virtual override(Yeye, Baba){
emit Log("Erzi");
}
function pop() public virtual override(Yeye, Baba) {
emit Log("Erzi");
}
我们可以看到,Erzi合约里面重写了hip()
和pop()
两个函数,将输出改为”Erzi”
,并且还分别从Yeye
和Baba
合约继承了yeye()
和baba()
两个函数。
Solidity中的修饰器(Modifier)同样可以继承,用法与函数继承类似,在相应的地方加virtual
和override
关键字即可。
子合约有两种方法继承父合约的构造函数。举个简单的例子,父合约A
里面有一个状态变量a,并由构造函数的参数来确定:
// 构造函数的继承
abstract contract A {
uint public a;
constructor(uint _a) {
a = _a;
}
}
contract B is A(1)
contract C is A {
constructor(uint _c) A(_c * _c) {}
}
子合约有两种方式调用父合约的函数,直接调用和利用super关键字。
父合约名.函数名()
的方式来调用父合约函数,例如Yeye.pop()
。 function callParent() public{
Yeye.pop();
}
super
关键字:子合约可以利用super.函数名()
来调用最近的父合约函数。solidity
继承关系按声明时从右到左的顺序是:contract Erzi is Yeye, Baba
,那么Baba
是最近的父合约,super.pop()
将调用Baba.pop()
而不是Yeye.pop()
: function callParentSuper() public{
// 将调用最近的父合约函数,Baba.pop()
super.pop();
}
这一讲,我们介绍了solidity
继承的基本用法,包括简单继承,多重继承,修饰器和构造函数的继承,以及调用父合约中的函数。