继承 #
一、继承概述 #
1.1 什么是继承 #
继承是Solidity中代码复用的主要方式,子合约可以继承父合约的状态变量、函数和修饰器。
solidity
contract Parent {
uint256 public value;
function setValue(uint256 _value) public {
value = _value;
}
}
contract Child is Parent {
function getValue() public view returns (uint256) {
return value; // 继承自Parent
}
}
1.2 继承的作用 #
| 作用 | 说明 |
|---|---|
| 代码复用 | 避免重复代码 |
| 功能扩展 | 在父合约基础上添加功能 |
| 模块化 | 分离关注点 |
| 标准实现 | 实现标准接口 |
二、单继承 #
2.1 基本语法 #
solidity
contract Parent {
uint256 public value;
function setValue(uint256 _value) public virtual {
value = _value;
}
}
contract Child is Parent {
function doubleValue() public {
value *= 2;
}
}
2.2 继承示例 #
solidity
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Invalid address");
owner = newOwner;
}
}
contract Token is Ownable {
string public name;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor(string memory _name, uint256 _supply) {
name = _name;
totalSupply = _supply;
balanceOf[msg.sender] = _supply;
}
function mint(address to, uint256 amount) public onlyOwner {
totalSupply += amount;
balanceOf[to] += amount;
}
}
三、多继承 #
3.1 基本语法 #
solidity
contract A {
function foo() public pure virtual returns (string memory) {
return "A";
}
}
contract B {
function bar() public pure virtual returns (string memory) {
return "B";
}
}
contract C is A, B {
function test() public pure returns (string memory, string memory) {
return (foo(), bar());
}
}
3.2 继承顺序 #
solidity
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, B {
// C继承A和B,B继承A
// 钻石继承问题:C的foo()来自B
function foo() public pure override(A, B) returns (string memory) {
return "C";
}
}
3.3 多继承示例 #
solidity
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
}
contract Pausable {
bool public paused;
modifier whenNotPaused() {
require(!paused, "Paused");
_;
}
function pause() public {
paused = true;
}
function unpause() public {
paused = false;
}
}
contract Token is Ownable, Pausable {
string public name;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor(string memory _name, uint256 _supply) {
name = _name;
totalSupply = _supply;
balanceOf[msg.sender] = _supply;
}
function transfer(address to, uint256 amount) public whenNotPaused {
require(balanceOf[msg.sender] >= amount, "Insufficient balance");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
}
function mint(address to, uint256 amount) public onlyOwner whenNotPaused {
totalSupply += amount;
balanceOf[to] += amount;
}
}
四、函数重写 #
4.1 virtual和override #
solidity
contract Parent {
// virtual:允许子合约重写
function getValue() public pure virtual returns (uint256) {
return 100;
}
}
contract Child is Parent {
// override:重写父合约函数
function getValue() public pure override returns (uint256) {
return 200;
}
}
4.2 多重重写 #
solidity
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, B {
// 重写多个父合约的同一函数
function foo() public pure override(A, B) returns (string memory) {
return "C";
}
}
4.3 调用父合约函数 #
solidity
contract Parent {
uint256 public value;
function setValue(uint256 _value) public virtual {
value = _value;
}
}
contract Child is Parent {
function setValue(uint256 _value) public override {
// 调用父合约函数
super.setValue(_value);
// 或者
Parent.setValue(_value);
// 额外逻辑
value *= 2;
}
}
五、抽象合约 #
5.1 定义抽象合约 #
solidity
abstract contract Animal {
// 抽象函数:没有实现
function makeSound() public pure virtual returns (string memory);
// 具体函数:有实现
function sleep() public pure returns (string memory) {
return "Zzz...";
}
}
contract Dog is Animal {
function makeSound() public pure override returns (string memory) {
return "Woof!";
}
}
contract Cat is Animal {
function makeSound() public pure override returns (string memory) {
return "Meow!";
}
}
5.2 抽象合约示例 #
solidity
abstract contract ERC20Interface {
function totalSupply() public view virtual returns (uint256);
function balanceOf(address owner) public view virtual returns (uint256);
function transfer(address to, uint256 value) public virtual returns (bool);
function allowance(address owner, address spender) public view virtual returns (uint256);
function approve(address spender, uint256 value) public virtual returns (bool);
function transferFrom(address from, address to, uint256 value) public virtual returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract MyToken is ERC20Interface {
string public name;
string public symbol;
uint8 public decimals;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 totalSupply_) {
name = _name;
symbol = _symbol;
decimals = _decimals;
_totalSupply = totalSupply_;
_balances[msg.sender] = totalSupply_;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address owner) public view override returns (uint256) {
return _balances[owner];
}
function transfer(address to, uint256 value) public override returns (bool) {
require(_balances[msg.sender] >= value, "Insufficient balance");
_balances[msg.sender] -= value;
_balances[to] += value;
emit Transfer(msg.sender, to, value);
return true;
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public override returns (bool) {
_allowances[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public override returns (bool) {
require(_balances[from] >= value, "Insufficient balance");
require(_allowances[from][msg.sender] >= value, "Insufficient allowance");
_balances[from] -= value;
_balances[to] += value;
_allowances[from][msg.sender] -= value;
emit Transfer(from, to, value);
return true;
}
}
六、构造函数继承 #
6.1 父合约构造函数 #
solidity
contract Parent {
uint256 public value;
constructor(uint256 _value) {
value = _value;
}
}
// 方式1:在声明时调用
contract Child1 is Parent(100) {
}
// 方式2:在子合约构造函数中调用
contract Child2 is Parent {
constructor(uint256 _value) Parent(_value) {
}
}
6.2 多继承构造函数 #
solidity
contract A {
uint256 public a;
constructor(uint256 _a) {
a = _a;
}
}
contract B {
uint256 public b;
constructor(uint256 _b) {
b = _b;
}
}
contract C is A, B {
constructor(uint256 _a, uint256 _b) A(_a) B(_b) {
}
}
七、super关键字 #
7.1 调用父合约 #
solidity
contract A {
event Log(string message);
function foo() public virtual {
emit Log("A.foo");
}
}
contract B is A {
function foo() public virtual override {
emit Log("B.foo");
super.foo(); // 调用A.foo()
}
}
contract C is A {
function foo() public virtual override {
emit Log("C.foo");
super.foo(); // 调用A.foo()
}
}
contract D is B, C {
function foo() public override(B, C) {
emit Log("D.foo");
super.foo(); // 调用C.foo() -> B.foo() -> A.foo()
}
}
八、最佳实践 #
8.1 合理使用继承 #
solidity
// 推荐:使用继承复用通用功能
contract Ownable {
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
}
contract Pausable {
bool public paused;
modifier whenNotPaused() {
require(!paused, "Paused");
_;
}
}
// 组合使用
contract MyContract is Ownable, Pausable {
function sensitiveOperation() public onlyOwner whenNotPaused {
// 敏感操作
}
}
8.2 避免深层继承 #
solidity
// 不推荐:过深的继承层次
// A -> B -> C -> D -> E
// 推荐:扁平的继承结构
// 使用组合代替深层继承
九、总结 #
继承要点:
| 特性 | 说明 |
|---|---|
| is | 继承关键字 |
| virtual | 允许重写 |
| override | 重写父合约函数 |
| super | 调用父合约函数 |
| abstract | 抽象合约 |
使用建议:
- 合理使用继承复用代码
- 避免过深的继承层次
- 使用virtual/override明确重写
- 使用抽象合约定义接口
接下来,让我们学习接口!
最后更新:2026-03-27