{"content":{"title":"Solidity 继承","body":"从头实现一个 ERC20 合约无疑会让人感到疲惫。Solidity 的行为类似于面向对象的语言，并且允许继承。这里是一个最小的示例。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    function theMeaningOfLife()\r\n        public\r\n        pure\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\ncontract Child is Parent {\r\n\r\n}\r\n\r\n```\r\n\r\n部署到 Remix 时，从下拉菜单中选择 Child 而不是 Parent 进行部署。\r\n\r\n![https://static.wixstatic.com/media/61a666_843d766cb40445de9d21657f94bfa237~mv2.png/v1/fill/w_939,h_610,al_c,q_95,enc_auto/Inheritance1.png](https://img.learnblockchain.cn/2025/02/26/Inheritance1.png)\r\n\r\n即使 Child 是空的，我们也能在 Child 中看到该函数。\r\n\r\n![https://static.wixstatic.com/media/61a666_fb428cb0a1aa4236950028fcf7a1db70~mv2.png/v1/fill/w_939,h_595,al_c,q_95,enc_auto/Inheritance2.png](https://img.learnblockchain.cn/2025/02/26/Inheritance2.png)\r\n\r\n当一个“合约” **是** “另一个合约”时，它继承了所有的功能。\r\n\r\n与其他面向对象编程语言一样，函数可以被重写。以下是更改值的构造。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    function theMeaningOfLife()\r\n        public\r\n        pure\r\n        virtual\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\ncontract Child is Parent {\r\n    function theMeaningOfLife()\r\n        public\r\n        pure\r\n        override\r\n        returns (uint256) {\r\n            return 43;\r\n    }\r\n}\r\n\r\n```\r\n\r\n![https://static.wixstatic.com/media/61a666_31b8d5b723244b1d91878f40900d7a97~mv2.png/v1/fill/w_939,h_434,al_c,q_95,enc_auto/Inheritance3.png](https://img.learnblockchain.cn/2025/02/26/Inheritance3.png)\r\n\r\n请注意，只有 **virtual** 函数才能被重写。如果你尝试重写一个不是 virtual 的函数，代码将无法编译。\r\n\r\n此外，当一个函数进行重写时，它必须完全匹配，包括名称、参数和返回类型。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    function theMeaningOfLife()\r\n        public\r\n        pure\r\n        virtual\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\ncontract Child is Parent {\r\n\r\n    // 无效：有不同的参数\r\n    function theMeaningOfLife(uint256 x)\r\n        public\r\n        pure\r\n        override\r\n        returns (uint256) {\r\n            return 42 + x;\r\n    }\r\n\r\n    // 无效：有不同的返回类型\r\n    function theMeaningOfLife(uint256 x)\r\n        public\r\n        pure\r\n        override\r\n        returns (bool) {\r\n            return true;\r\n    }\r\n\r\n    // 无效：有不同的名称\r\n    function theMeaningOfLif3(uint256 x)\r\n        public\r\n        pure\r\n        override\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\n```\r\n\r\nSolidity 支持多重继承。\r\n\r\n```solidity\r\n\r\ncontract Parent1 {\r\n    function theMeaningOfLife()\r\n        public\r\n        pure\r\n        virtual\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\ncontract Parent2 {\r\n    function hackerFavoriteNumber()\r\n        public\r\n        pure\r\n        virtual\r\n        returns (uint256) {\r\n            return 1337;\r\n    }\r\n}\r\n\r\ncontract Child is Parent1, Parent2 {\r\n\r\n}\r\n\r\n```\r\n\r\n如果你想知道，如果两个父类有一个同名的函数，子类必须重写它，否则其行为将会产生歧义。如果你陷入这种情况，你可能在软件设计中做错了事情。 所以让我们不要走这条路。\r\n\r\n**私有 vs 内部**\r\n\r\n有两种方法可以使一个函数不从外部世界可访问：给予它们一个 private 或 internal 修饰符。区分非常简单。\r\n\r\n私有函数（和变量）不能被子合约“看到”。\r\n\r\n内部函数和变量可以。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    function foo()\r\n        internal\r\n        pure\r\n        virtual\r\n        returns (string memory) {\r\n            return \"foo\";\r\n    }\r\n\r\n    // 错误！私有函数不能被重写，\r\n    // 所以将其设置为 virtual 没有意义！\r\n    function bar()\r\n        private\r\n        pure\r\n        virtual\r\n        returns (string memory) {\r\n            return \"bar\";\r\n    }\r\n}\r\n\r\n```\r\n\r\n**super 关键字**\r\n\r\nsuper 关键字意味着“调用父类的函数。”以下是它如何使用：\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    function foo()\r\n        internal\r\n        pure\r\n        virtual\r\n        returns (string memory) {\r\n            return \"foo\";\r\n    }\r\n}\r\n\r\ncontract Child is Parent {\r\n\r\n        // 我们重写了 foo 使其为 public\r\n    function foo()\r\n        public\r\n        pure\r\n        override\r\n        returns (string memory) {\r\n            return super.foo();\r\n    }\r\n}\r\n\r\n```\r\n\r\n如果我们在这里不包含 super 关键字，foo() 将调用自身并进入无限递归。尝试去掉 super 并在 Remix 中运行代码。交易将因无限递归而回退（以太坊不允许代码永远运行，它会强制终止它们。确切机制是一个后续讨论的中间主题）。\r\n\r\nSuper 意味着“调用父类的 foo，而不是我的。”这让我们可以获得 foo 的所有功能，而不必复制和粘贴代码。\r\n\r\n**调用父类的构造函数**\r\n\r\nSolidity 不允许你从父合约继承而不初始化其构造函数。考虑这种情况。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n    string private name;\r\n\r\n    constructor(string memory _name) {\r\n        name = _name;\r\n    }\r\n\r\n    function getName() public view virtual returns (string memory) {\r\n        return name;\r\n    }\r\n}\r\n\r\ncontract Child is Parent {\r\n\r\n    // 错误，name 尚未设置！\r\n    function getName() public view override returns (string memory) {\r\n        return super.getName();\r\n    }\r\n}\r\n\r\n```\r\n\r\n解决方案是在继承时调用父类构造函数。\r\n\r\n```solidity\r\n\r\ncontract Parent {\r\n\r\n    string private name;\r\n\r\n    constructor(string memory _name) {\r\n        name = _name;\r\n    }\r\n\r\n    function getName()\r\n        public\r\n        view\r\n        virtual\r\n        returns (string memory) {\r\n            return name;\r\n    }\r\n}\r\n\r\n//修复\r\ncontract Child is Parent(\"The Beatles\") {\r\n    function getName()\r\n        public\r\n        view\r\n        override\r\n        returns (string memory) {\r\n            return super.getName();\r\n    }\r\n}\r\n\r\n```\r\n\r\n让我们总结一下我们所学到的内容\r\n\r\n- 只有 virtual 函数可以被重写\r\n- 重写父类函数的函数必须具有 override 修饰符\r\n- 重写函数的名称、参数和返回类型必须完全匹配\r\n- 可以使用 super 关键字，而不是复制和粘贴父函数的代码\r\n- 你可以从多个合约中继承\r\n- 继承时必须显式调用父构造函数。\r\n\r\n**创造一个轻松的 ERC20 代币**\r\n\r\n继承结合 import 语句，使我们能够轻松利用其他人创建的库。将此合约部署到 Remix 中，你将看到所有 ERC20 函数都已为你实现。\r\n\r\n```solidity\r\n\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract Token is ERC20(\"SomeToken\", \"symbol\") {\r\n\r\n}\r\n\r\n```\r\n\r\n \r\n\r\n**澄清说明**\r\n\r\n智能合约作为 Solidity 对象与部署在区块链上的智能合约之间有明显的区别。\r\n\r\n**你无法继承部署在区块链上的合约。**\r\n\r\n它们是生存于你之外的二进制块。由于模糊的术语，一些 Solidity 开发人员担心函数和变量可以被恶意合约继承和重写。**这不可能发生。** 尽管我们将部署代码称为“合约”，而将 Solidity 代码称为“合约”，但它们并不是相同的东西。\r\n\r\n**练习问题**\r\n\r\n[InheritanceOverride](https://github.com/RareSkills/Solidity-Exercises/tree/main/InheritanceOverride)\r\n\r\n[MultiInheritance](https://github.com/RareSkills/Solidity-Exercises/tree/main/MultiInheritance)\r\n\r\n[Super](https://github.com/RareSkills/Solidity-Exercises/tree/main/Super)\r\n\r\n[AccessModifiers](https://github.com/RareSkills/Solidity-Exercises/tree/main/AccessModifiers)\r\n\r\n###  学习更多\r\n\r\n查看  [Solidity 训练营](https://learnblockchain.cn/openspace/1) ，以了解更多关于智能合约开发和代币标准的内容。\r\n\r\n \r\n\r\n>- 原文链接： [rareskills.io/learn-soli...](https://www.rareskills.io/learn-solidity/inheritance)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/20722","address":null},"history":null,"timestamp":1740625380,"version":1}