10. Solidity:继承

2023-10-05  本文已影响0人  泡泡龙吐泡泡

10.1 单继承

继承是面向对象编程很重要的组成部分,可以显著减少重复代码。如果把合约看作是对象的话,solidity也是面向对象的编程,也支持继承。

10.1.1 virtual和override

10.1.2 例子

contract Animal {

    function getName() public pure virtual returns (string memory) {
        return "Animal";
    } 

    function walk() public pure virtual returns (string memory) {
        return "walk";
    }
}

contract Dog is Animal {

    function getName() public pure override returns (string memory) {
        return "Dog";
    }

}

10.2 多线继承

solidity中支持多继承,即一个合约可以继承自多个合约。我们再定义一个Keji合约,继承自Animal和Dog两个合约。
继承结构如下:

//    Animal
//    /    \
//   Dog    \
//    \     /
//     \   /
//     Keji

示例代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract Animal {

    function getName() public pure virtual returns (string memory) {
        return "Animal";
    } 

    function walk() public pure virtual returns (string memory) {
        return "walk";
    }
}


contract Dog is Animal {

    function getName() public pure override virtual returns (string memory) {
        return "Dog";
    }

    function speak() public pure virtual returns (string memory) {
        return "Wang Wang";
    }
}

contract Keji is Animal, Dog {
    function getName() public pure override(Dog, Animal) returns (string memory) {
        return "Keji";
    }
}

注意:

10.3 菱形继承(钻石继承)

我们构造一种继承关系,B和C合约继承A合约,而D合约由继承B和C合约,继承关系如下:

//      A
//    /   \
//   B     C
//    \   /
//      D

这种继承机构称为菱形继承或者钻石继承。示例代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;


contract A {
    event Log(string message);

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

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

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

    function bar() public override  virtual {
        super.bar();
        emit Log("B.bar");
    }
}

contract C is A {
    function foo() public override  virtual {
        A.foo();
        emit Log("C.foo");
    }
    function bar() public override  virtual {
        super.bar();
        emit Log("C.bar");
    }
}

contract D is B,C {
    function foo() public override(B,C)  virtual {
        B.foo();
        emit Log("D.foo");
    }

    function bar() public override(B,C)  virtual {
        super.bar();
        emit Log("D.bar");
    }
}

注意:

// *****************************  foo()  *****************************
[
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "A.foo",
            "message": "A.foo"
        }
    },
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "B.foo",
            "message": "B.foo"
        }
    },
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "D.foo",
            "message": "D.foo"
        }
    }
]
// *****************************  bar()  *****************************
[
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "A.bar",
            "message": "A.bar"
        }
    },
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "B.bar",
            "message": "B.bar"
        }
    },
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "C.bar",
            "message": "C.bar"
        }
    },
    {
        "from": "0xad153c5e12dB58a47f2454691b26582A430803fB",
        "topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab",
        "event": "Log",
        "args": {
            "0": "D.bar",
            "message": "D.bar"
        }
    }
]

10.4 修饰器继承

Solidity中的修饰器(Modifier)同样可以继承,用法与函数继承类似,在相应的地方加virtual和override关键字即可。

contract A {

    modifier requireGreater(uint _a) virtual  {
        require(_a > 5, "Require greater than 5");
        _;
    }
}

contract B is A {
    function double(uint _a) public pure requireGreater(_a) returns (uint){
        return _a * 2;
    }
}

重写修饰器:

contract C is A {
    modifier requireGreater(uint _a) override  {
        require(_a > 10, "Require greater than 10");
        _;
    }
    function double(uint _a) public pure requireGreater(_a) returns (uint){
        return _a * 2;
    }
}

10.5 构造函数继承

子合约有两种方法继承父合约的构造函数。举个简单的例子,父合约A里面有一个状态变量a,并由构造函数的参数来确定:

contract A {
    uint public a;

    constructor(uint _a) {
        a = _a;
    }
}

方法一:在继承时传入父构造函数的参数

contract B is A(5) {}

方法二:在子合约的构造函数中声明构造函数的参数

contract C is A {
    constructor(uint _a) A(_a*2){}
}
上一篇 下一篇

猜你喜欢

热点阅读