继承 #

一、继承概述 #

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