跳转至

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();
    }
}