Solidity virtual和override关键字

关键字virtual和override在Solidity中可用于函数覆盖

这些关键字的目的在于,当合约被继承后子合约覆盖函数将更为明确。如果父合约的某个函数被标记为virtual关键字,那么他的子合约可以通过override关键字来覆盖父函数。

但在使用这两个关键字的同时需要注意以下几点:

  • 对于多重继承,必须在override关键字后指定定义相同函数的派生最基础的合约;

  • 具有private可见性的函数是不能被virtual修饰的;

  • 在抽象合约中,没有实现的函数(抽象函数)必须要被virtual关键字修饰。而在接口合约中,所有的函数都会被自动修饰上virtual(不需要添加virtual关键字);

virtual和override关键字示例:

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

contract Base {
    function foo() virtual public {}
}

contract Middle is Base {}

contract Inherited is Middle {
    function foo() public override {}
}

多重继承示例:

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

/*
   X
 / |
Y  |
 \ |
   Z
这样的顺序是 is X,Y 因为X最基础,Y只是他的派生

   X
  / \
 Y   A
 |   |
 |   B
  \ /
   Z
顺序是 is X,Y,A,B
*/
contract X{
    // 注意父类方法标注了virtual 关键字,则子类必须要重写该方法
    function foo() public pure virtual returns (string memory){
        return "X";
    }

    function bar() public pure virtual returns (string memory){
        return "X";
    }

    function x() public pure virtual returns (string memory){
        return "X";
    }

}

contract Y is X{
    function foo() public pure virtual override returns (string memory){
        return "Y";
    }

    function bar() public pure virtual override returns (string memory){
        return "Y";
    }
    
    function y() public pure returns (string memory){
        return "Y";
    }
}

contract Z is X,Y{
    // 需要标注函数重写自谁
    function foo() public pure override(X,Y) returns (string memory){
        return "Z";
    }

    function bar() public pure override(Y,X) returns (string memory){
        return "Z";
    }
}

参考资料

Solidity 中的 virtual 和 override 关键字是什么?