solidity 支持多继承,通过关键字 is 实现,继承的合约可以直接访问父合约的public,internal权限的变量或函数
1.继承与构造函数
- 有两种方法初始化父类合约,如contract A 、contract B
- 在继承的时候,父构造函数总是按照继承的顺序调用,跟子合约中父类的构造函数的顺序无关,如contract B、contract C
pragma solidity ^0.8.0;
contract X {
string x;
constructor(string memory _x){
x = _x;
}
}
contract Y {
string y;
constructor(string memory _y){
y = _y;
}
}
contract A is X("hello x"),Y("hello y"){
string a;
constructor(string memory _a){
a = _a;
}
}
// 构造函数调用顺序
// X -> Y - >B
contract B is X,Y{
string a;
constructor(string memory _a,string memory _x,string memory _y)X(_x) Y(_y){
a = _a;
}
}
// 构造函数调用顺序
// X -> Y - >C
contract C is X,Y{
string a;
constructor(string memory _a,string memory _x,string memory _y) Y(_y) X(_x){
a = _a;
}
}
2.继承与虚函数
父合约标记为 virtual
函数可以在子合约里进行重写,重写的函数需要使用关键字 override
修饰。
pragma solidity ^0.8.0;
contract X{
function f() public virtual pure returns(string memory){
return "xf";
}
}
contract Y is X{
function f() public virtual override pure returns(string memory){
return "yf";
}
}
如果多继承中,父合约有相同的virtual函数,则override
关键字后必须指定所有父合约名
pragma solidity ^0.8.0;
contract X{
function f() public virtual pure returns(string memory){
return "xf";
}
}
contract Y{
function f() public virtual pure returns(string memory){
return "yf";
}
}
contract Z is X,Y{
function f() public pure override(X,Y) returns(string memory){
return "zf";
}
}
3.继承与父合约调用
- 可以使用
super
关键字或父合同名称调用父合同的函数 - 使用
super
关键字,最近的父类合约( immediate parent contracts)也会被调用
pragma solidity ^0.8.10;
/* Inheritance tree
A
/ \
B C
\ /
D
*/
contract A {
event Log(string message);
function foo() public virtual {
emit Log("A.foo called");
}
function bar() public virtual {
emit Log("A.bar called");
}
}
contract B is A {
function foo() public virtual override {
emit Log("B.foo called");
A.foo();
}
function bar() public virtual override {
emit Log("B.bar called");
super.bar();
}
}
contract C is A {
function foo() public virtual override {
emit Log("C.foo called");
A.foo();
}
function bar() public virtual override {
emit Log("C.bar called");
super.bar();
}
}
contract D is B, C {
//C.foo called
//A.foo called
function foo() public override(B, C) {
super.foo();
}
//C.bar called
//B.bar called
//A.bar called
function bar() public override(B, C) {
super.bar();
}
}
4.继承规则
- 多重继承时,当一个函数在多个父函数定义,子合约调用该函数是遵循从右到左的原则,如contract A和contract B
- 多重继承时需要按照从“最接近的基类”(most base-like)到“最远的继承”(most derived)的顺序来指定所有的基类,如contract C
pragma solidity ^0.8.0;
contract X {
function foo()public virtual pure returns(string memory){
return "X";
}
}
contract Y is X{
function foo()public virtual override pure returns(string memory){
return "Y";
}
}
contract Z is X{
function foo()public virtual override pure returns(string memory){
return "Z";
}
}
contract A is Y,Z{
function foo()public virtual override(Y,Z) pure returns(string memory){
return super.foo(); //return Z
}
}
contract B is Z,Y{
function foo()public virtual override(Y,Z) pure returns(string memory){
return super.foo(); //return Y
}
}
/*
X
/ \
Y Z
/ \ /
C A,B
contract C is Y,X{} //这种继承顺序会报:Linearization of inheritance graph impossible
*/
contract C is X,Y{
function foo()public virtual override(X,Y) pure returns(string memory){
return super.foo(); //return Y
}
}