【Solidity】继承

继承

Solidity 中使用 is 关键字实现继承,子合约可以继承父合约的状态变量、函数、事件、装饰器:

contract Father {
    // 声明事件
    event Log(string message, address sender);

    // 声明状态变量
    uint public a = 10;
    address public owner = msg.sender;

    // 声明装饰器
    modifier onlyOwner() {
        require(msg.sender == owner, "You are not the owner");
        _;
    }

    // 声明函数
    function setA(uint _a) public {
        a = _a;
    }
}

contract Son is Father {
    function testEvent() public onlyOwner {
        emit Log("Son", msg.sender);
    }
}
  1. 部署 Son 合约

  2. 可以看到 Son 合约继承了 Father 合约的状态变量和函数

  3. 调用 Son 合约的 testEvent 方法,可以看到触发了 Father 合约的事件

  4. 用其他账户调用 Son 合约的 testEvent 方法,会报错,可知 Son 合约继承了 Father 合约的修饰器



重写函数

  • 使用 virtual 关键字标记父合约中的函数,表示该函数可以在子合约中被重写

  • 使用 override 关键字标记子合约中的函数,表示该函数重写了父合约中的函数

contract Father {
    function getNumber1() public pure returns (uint) {
        return 10;
    }

    function getNumber2() public pure virtual returns (uint) {
        return 20;
    }
}

contract Son is Father {
    function getNumber2() public pure override returns (uint) {
        return 40;
    }
}



重写装饰器

规则与重写函数相同。

contract Father {
    modifier limit(uint256 _value) virtual {
        require(_value > 0 && _value < 100, "value must be between 0 and 100");
        _;
    }
}

contract Son is Father {
    modifier limit(uint256 _value) override {
        require(_value > 0 && _value < 10, "value must be between 0 and 10");
        _;
    }
}



多级继承

contract A {
    function getNumber1() public pure returns (uint) {
        return 10;
    }

    function getNumber2() public pure virtual returns (uint) {
        return 20;
    }

    function getNumber3() public pure virtual returns (uint) {
        return 30;
    }
}

contract B is A {
    function getNumber2() public pure override returns (uint) {
        return 40;
    }

    // 用 virtual 和 override 同时修饰方法
    function getNumber3() public pure virtual override returns (uint) {
        return 50;
    }
}

contract C is B {
    function getNumber3() public pure override returns (uint) {
        return 60;
    }
}



多重继承

多重继承允许一个合约继承多个父合约。

规则:

  • 继承顺序:继承时要按辈分从高到低排序。

  • 函数重写:如果多个父合约中存在同名函数,子合约必须重写该函数,并在 override 关键字后面列出所有父合约的名字。

   X
 / |
Y  |
 \ |
   Z
contract X {
    function foo() public virtual returns (string memory) {
        return "X";
    }
}

contract Y is X {
    function foo() public virtual override returns (string memory) {
        return "Y";
    }
}

// 根据继承顺序, 先 X 后 Y
contract Z is X, Y {
    // override 里面的顺序无所谓
    function foo() public pure override(Y, X) returns (string memory) {
        return "Z";
    }
}



钻石继承 (菱形继承)

菱形继承 (钻石继承) 是多重继承的一种特殊情况。

  A
 / \
B   C
 \ /
  D
contract A {
    function foo() public pure virtual returns (string memory) {
        return "A";
    }
}

contract B is A {
    function foo() public pure virtual override returns (string memory) {
        return "B";
    }
}

contract C is A {
    function foo() public pure virtual override returns (string memory) {
        return "C";
    }
}
// 根据继承顺序, B C 平级, 所以顺序随意

contract D1 is B, C {
    function foo() public pure override(B, C) returns (string memory) {
        return "D1";
    }
}

contract D2 is C, B {
    function foo() public pure override(C, B) returns (string memory) {
        return "D2";
    }
}



调用父合约的构造函数

contract A {
    string public name;
    constructor(string memory _name) {
        name = _name;
    }
}

contract B {
    uint public number;
    constructor(uint _number) {
        number = _number;
    }
}

// 方法 1 - 在声明继承时调用
contract D is A("Hello"), B(42) {}

// 方法 2 - 在声明构造函数时调用
contract C is A, B {
    constructor(string memory _name, uint _number) A(_name) B(_number) {}
}

// 方法 1 和 2 可混用
contract E is A("Hello"), B {
    constructor(uint _number) B(_number) {}
}

构造函数的调用顺序:先继承的父合约 → 后继承的父合约 → 当前合约

所以,demo 1 是 A → B → C、 demo 2 是 A → B → D、 demo 3 是 A → B → E



调用父合约的方法

对于多重继承:

   X
 / |
Y  |
 \ |
   Z
contract A {
    event Log(string message);

    function func() public virtual {
        emit Log("A");
    }
}

contract B is A {
    function func() public virtual override {
        emit Log("B");
        super.func();
    }
}

contract C is A, B {
    function func() public virtual override(A, B) {
        // 方法 1 - 通过 super 调用, 会调用最近的父合约
        super.func(); // B - A

        // 方法 2 - 通过合约调用
        A.func(); // A
        B.func(); // B - A
    }
}

对于钻石继承:

  A
 / \
B   C
 \ /
  D
contract A {
    event Log(string message);

    function func() public virtual {
        emit Log("A");
    }
}

contract B is A {
    function func() public virtual override {
        emit Log("B");
        super.func();
    }
}

contract C is A {
    function func() public virtual override {
        emit Log("C");
        super.func();
    }
}
// 根据继承顺序, B C 平级, 所以顺序随意

// 先继承 C 再继承 B
contract D1 is C, B {
    function func() public override(B, C) {
        C.func(); // C - A
        B.func(); // B - C - A
        A.func(); // A
    }

    function funcD() public {
        super.func(); // B - C - A
    }
}

// 先继承 B 再继承 C
contract D2 is B, C {
    function func() public override(B, C) {
        C.func(); // C - B - A
        B.func(); // B - A
        A.func(); // A
    }

    function funcD() public {
        super.func(); // C - B - A
    }
}



猜你喜欢

转载自blog.csdn.net/Superman_H/article/details/141307160