virtual
: 父合约中函数希望子合约重写,需要加上virtual
关键字。override
:子合约重写了父合约中的函数,需要加上override
关键字。
使用关键字is
继承父合约
- 继承时要按辈分最高到最低的顺序排。比如我们写一个
Erzi
合约,继承Yeye
合约和Baba
合约,那么就要写成contract Erzi is Yeye, Baba
,而不能写成contract Erzi is Baba, Yeye
,不然就会报错。 - 如果某一个函数在多个继承的合约里都存在,比如例子中的
hip()
和pop()
,在子合约里必须重写,不然会报错。 - 重写在多个父合约中都重名的函数时,
override
关键字后面要加上所有父合约名字,例如override(Yeye, Baba)
。
在相应的地方加virtual
和override
关键字即可
有两种写法(一般使用第二种):
-
在继承时声明父构造函数的参数,例如:
contract B is A(1)
-
在子合约的构造函数中声明构造函数的参数,例如:
contract C is A { constructor(uint _c) A(_c * _c) {} }
两种方式:
- 直接调用: 子合约可以直接用
父合约名.函数名()
的方式来调用父合约函数,例如Yeye.pop()
super
关键字:子合约可以利用super.函数名()
来调用最近的父合约函数。
钻石继承由基类构成的DAG(有向无环图)使其保证一个特定的顺序。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/* 继承树:
God
/ \
Adam Eve
\ /
people
*/
contract God {
event Log(string message);
function foo() public virtual {
emit Log("God.foo called");
}
function bar() public virtual {
emit Log("God.bar called");
}
}
contract Adam is God {
function foo() public virtual override {
emit Log("Adam.foo called");
super.foo();
}
function bar() public virtual override {
emit Log("Adam.bar called");
super.bar();
}
}
contract Eve is God {
function foo() public virtual override {
emit Log("Eve.foo called");
super.foo();
}
function bar() public virtual override {
emit Log("Eve.bar called");
super.bar();
}
}
contract people is Adam, Eve {
function foo() public override(Adam, Eve) {
super.foo();
}
function bar() public override(Adam, Eve) {
super.bar();
}
}