19.Inheritance
Solidity支持多重继承。
合约可以使用"is"关键字继承其他合约。
将被子合约覆盖的函数必须声明为virtual。
将要覆盖父函数的函数必须使用关键字 override。
继承的顺序很重要。 您必须按照从“最基本的”到“最派生的”的顺序列出父合约。
Solidity supports multiple inheritance. Contracts can inherit other contract by using the is keyword.
Function that is going to be overridden by a child contract must be declared as virtual.
Function that is going to override a parent function must use the keyword override.
Order of inheritance is important.
You have to list the parent contracts in the order from “most base-like” to “most derived”.
继承¶
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract A {
function foo() public pure returns (string memory) {
return "A";
}
function bar() public pure returns (string memory) {
return "A";
}
function baz() public pure returns (string memory) {
return "A";
}
}
contract B {
function foo() public pure returns (string memory) {
return "B";
}
function bar() public pure returns (string memory) {
return "B";
}
}
想让B继承A
virtual: 说明可以继承且可以被改变
override:重写
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract A {
function foo() public pure virtual returns (string memory) {
return "A";
}
function bar() public pure virtual returns (string memory) {
return "A";
}
function baz() public pure returns (string memory) {
return "A";
}
}
contract B is A {
function foo() public pure override returns (string memory) {
return "B";
}
function bar() public pure virtual override returns (string memory) {
return "B";
}
}
contract C is B {
function bar() public pure override returns (string memory) {
return "C";
}
}
套娃继承¶
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
/*
X
/ |
Y |
\ |
Z
// order of most base like to derived
// X Y Z
*/
contract X {
function foo() public pure virtual returns (string memory) {
return "X";
}
function bar() public pure virtual returns (string memory) {
return "X";
}
function x() public pure returns (string memory) {
return "X";
}
}
contract Y is X {
function foo() public pure virtual override returns (string memory) {
return "Y";
}
function bar() public pure virtual override returns (string memory) {
return "Y";
}
function y() public pure returns (string memory) {
return "y";
}
}
contract Z is X, Y {
function foo() public pure override(X, Y) returns (string memory) {
return "Z";
}
function bar() public pure override(X, Y) returns (string memory) {
return "Z";
}
}
继承顺序¶
/*
X
/ \
Y A
| |
| B
\ |
Z
// order of most base like to derived
// X, Y, A, B, Z
*/
Shadowing Inherited State Variables¶
和function不一样,state variable不能通过重新声明的方式被子合约继承
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract A {
string public name = "Contract A";
function getName() public view returns (string memory) {
return name;
}
}
// Shadowing is disallowed in Solidity 0.6
// This will not compile
// contract B is A {
// string public name = "Contract B";
// }
contract C is A {
// This is the correct way to override inherited state variables.
constructor() {
name = "Contract C";
}
// C.getName returns "Contract C"
}
super¶
Parent contracts can be called directly, or by using the keyword super.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
/* Inheritance tree
A
/ \
B C
\ /
D
*/
// A B C D
contract A {
// This is called an event. You can emit events from your function
// and they are logged into the transaction log.
// In our case, this will be useful for tracing function calls.
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 {
// Try:
// - Call D.foo and check the transaction logs.
// Although D inherits A, B and C, it only called C and then A.
// - Call D.bar and check the transaction logs
// D called C, then B, and finally A.
// Although super was called twice (by B and C) it only called A once.
function foo() public override(B, C) {
super.foo();
}
function bar() public override(B, C) {
super.bar();
}
}