Solidity中的继承

  • Louis
  • 更新于 2024-11-28 10:11
  • 阅读 1328

Solidity是一种面向对象的编程语言,它支持合约之间的继承。继承允许一个合约获取另一个合约的所有非私有属性和函数,这样就可以重复使用代码,降低重复工作量。继承关键字在Solidity中,继承是通过is关键字来实现的。

基本概念

Solidity是一种面向对象的编程语言,它支持合约之间的继承。继承允许一个合约获取另一个合约的所有非私有属性和函数,这样就可以重复使用代码,降低重复工作量。

继承关键字

在Solidity中,继承是通过is关键字来实现的。

virtualoverride 关键字

在 Solidity 0.6.0 版本及以后,引入了 virtualoverride 关键字用来显式控制函数和状态变量的可重写性。在实际开发中,使用 virtualoverride 是最佳实践,以确保合约的可读性和安全性。

  • virtual:用于标记父合约中的函数,表示该函数可以在子合约中被重写。
  • override:用于标记子合约中的函数,表示该函数重写了父合约中的函数。

继承的示例

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

// 定义父合约
contract Parent {
    string public name;
    uint public age;

    // 构造函数
    constructor(string memory _name, uint _age) {
        name = _name;
        age = _age;
    }

    // 设置名称函数
    function setName(string memory _name) public virtual {
        name = _name;
    }

    // 设置年龄函数
    function setAge(uint _age) public virtual {
        age = _age;
    }
}

// 定义子合约,继承自 Parent
contract Child is Parent {
    string public school;

    // 构造函数
    constructor(string memory _name, uint _age, string memory _school) Parent(_name, _age) {
        school = _school;
    }

    // 设置学校函数
    function setSchool(string memory _school) public {
        school = _school;
    }

    // 重载父合约的 setName 函数
    function setName(string memory _name, string memory _school) public override {
        name = _name;
        school = _school;
    }

    // 调用父合约的 setAge 函数
    function incrementAge() public {
        setAge(age + 1);
    }

    // 获取所有信息
    function getInfo() public view returns (string memory, uint, string memory) {
        return (name, age, school);
    }
}

详细解释

  1. 父合约 Parent

    • setNamesetAge 函数使用了 virtual 关键字,表示这些函数可以在子合约中被重写。
  2. 子合约 Child

    • setName 函数使用了 override 关键字,表示它重写了父合约中的 setName 函数。
  3. 构造函数

    • 子合约的构造函数调用了父合约的构造函数,初始化 nameage,同时初始化 school

一个常用的业务场景

我们肯定都写过 ERC20 Token,使用 openzeppelin 库去实现

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
  constructor(string memory name, string memory symbol,uint256 initialSupply) ERC20(name, symbol) {
    _mint(msg.sender, initialSupply);
  }
}

在上面的智能合约中,_mint 方法是来自 OpenZeppelin 的 ERC20 合约中的 internal 方法,允许在合约内部调用,但外部合约或账户无法直接调用。ERC20 合约定义了 _mintinternal,这意味着它只能在继承自 ERC20 的合约内部或同一合约的继承链中使用。

我们在合约的构造函数中调用了 _mint,这是一种规范的做法,因为:

  1. 构造函数是合约的一部分,它在合约部署时被执行。由于构造函数属于合约的内部执行逻辑,因此可以调用 internal 方法。
  2. 我们的Token合约继承自 ERC20 合约,所以 _mint 方法在你的 Token 合约内是可见的。internal 方法可以在合约内部或其子合约中调用,所以在你的 Token 合约的构造函数中调用 _mint 是有效的。

简而言之,_mintERC20 合约中的一个 internal 方法,它允许子合约(如你当前的 Token 合约)在其构造函数或其他内部函数中调用。这也是为什么你可以在构造函数中使用它来为部署者铸造初始代币供应。

使用 virtualoverride 的好处

  • 明确的可重写性:使用 virtualoverride 明确标识哪些函数可以被重写,增加代码的可读性。
  • 防止错误:防止因意外重写函数而引入的错误,确保重写操作是显式和有意的。
  • 增强安全性:提高智能合约的安全性,防止意外的函数重写行为。
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Louis
Louis
web3 developer,技术交流或者有工作机会可加VX: magicalLouis