第七章 | Solidity 合约继承与接口全面讲解
之前我们写的合约都比较“单一”,但在真正的区块链项目里,复杂合约系统往往由多个合约协作组成。
比如:
要做到功能分离、模块清晰、代码复用,必须掌握 Solidity 的继承和接口。
这一章,我们把基础打扎实,同时搞清楚多继承、函数重写这些细节问题。
继承允许一个合约重用另一个合约的逻辑代码,提高复用性、简化代码结构。
Solidity 支持单继承和多继承。
父合约 BaseContract
,子合约 ChildContract
:
contract BaseContract {
uint public baseValue;
function setBaseValue(uint _value) public {
baseValue = _value;
}
}
contract ChildContract is BaseContract {
function getBaseValue() public view returns (uint) {
return baseValue;
}
}
说明
ChildContract
自动继承了 BaseContract
的状态变量和函数ChildContract
直接访问 baseValue
和 setBaseValue()
is
表示继承关系virtual
override
示例
contract Parent {
function foo() public pure virtual returns (string memory) {
return "Parent";
}
}
contract Child is Parent {
function foo() public pure override returns (string memory) {
return "Child";
}
}
在子合约里通过 super
关键字调用父合约方法
contract Parent {
function greet() public pure virtual returns (string memory) {
return "Hello from Parent";
}
}
contract Child is Parent {
function greet() public pure override returns (string memory) {
return super.greet();
}
}
⚠️ 常见坑
virtual
,子合约无法 override
super
调用的是线性继承顺序,具体看 C3 线性化算法(后面讲)abstract contract AbstractContract {
function doSomething() public virtual;
}
contract ConcreteContract is AbstractContract {
function doSomething() public override {
// 实现逻辑
}
}
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
}
contract MyToken is IERC20 {
function totalSupply() external pure override returns (uint) { return 10000; }
function balanceOf(address account) external pure override returns (uint) { return 1000; }
function transfer(address recipient, uint amount) external override returns (bool) { return true; }
}
Solidity 支持多继承,子合约可以继承多个父合约
contract A { function foo() public pure virtual returns (string memory) { return "A"; } }
contract B { function foo() public pure virtual returns (string memory) { return "B"; } }
contract C is A, B {
function foo() public pure override(A, B) returns (string memory) {
return super.foo(); // 依赖继承顺序,按 C3 线性化算法
}
}
super
调用// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
// 提案接口
interface IProposal {
function executeProposal(uint proposalId) external;
}
// 治理基础合约
abstract contract Governance {
address public chairperson;
mapping(address => uint) public votes;
constructor() {
chairperson = msg.sender;
}
modifier onlyChairperson() {
require(msg.sender == chairperson, "Not chairperson");
_;
}
function vote(address voter, uint weight) public virtual;
}
// DAO 合约继承治理基础合约,实现提案接口
contract MyDAO is Governance, IProposal {
uint public totalVotes;
function vote(address voter, uint weight) public override {
votes[voter] += weight;
totalVotes += weight;
}
function executeProposal(uint proposalId) external override onlyChairperson {
// 执行提案逻辑
}
}
Governance
作为抽象治理合约,定义基本权限IProposal
标准接口,统一提案执行逻辑MyDAO
继承治理 + 提案,实现完整 DAO 功能onlyChairperson
权限修饰符保护提案执行入口virtual
才能被重写override
必须明确指定父合约super
行为异常virtual
,继承时编译报错override
,子合约逻辑未生效这一章,我们深入学习了 Solidity 合约继承与接口:
✔️ 合约继承基本用法
✔️ 函数重写、super
调用父合约
✔️ 抽象合约应用
✔️ 接口标准化设计
✔️ 多继承冲突解决
✔️ 实战构建 DAO 合约架构
函数修饰符与访问控制模式
modifier
进阶玩法
Ownable / AccessControl 权限系统
角色授权、治理模型实战
安全设计避免权限泄露
OpenZeppelin 权限系统实战