抽象合约
在 Solidity
中,接口、抽象合约、与合约的抽象程度大致如下:
抽象合约介于接口与具体合约之间。抽象合约与具体的合约最本质的区别在于抽象合约不能够被实例化。
抽象合约中往往存在未被具体实现的虚(virtual)函数。
抽象合约声明
抽象合约通过 abstract contract
声明:
AbstractContract.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
abstract contract Greeting {
function sayHi() external virtual returns (string memory);
function sayBye() external virtual returns (string memory);
}
抽象合约继承抽象合约
一个抽象合约可以继承另一个抽象合约:
AbstractContract.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
abstract contract Greeting {
function sayHi() external virtual returns (string memory);
function sayBye() external virtual returns (string memory);
}
// 继承另一个抽象合约,只实现其中的 sayHi 虚函数
abstract contract SubGreeting is Greeting {
function sayHi() external pure override returns (string memory) {
return "Hi";
}
}
一个合约如果继承于另一个抽象合约,且未完全实现抽象合约中未实现的虚函数,则该合约也必须标志为抽象合约,如上例的 SubGreeting
未实现 sayBye
函数,因此该合约也必须声明为抽象合约。
具体合约继承抽象合约
继承于抽象合约的具体合约,必须实现抽象合约中的所有虚函数。
AbstractContract.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
abstract contract Greeting {
function sayHi() external virtual returns (string memory);
function sayBye() external virtual returns (string memory);
}
// 继承另一个抽象合约,只实现其中的 sayHi 虚函数
abstract contract SubGreeting is Greeting {
function sayHi() external pure override returns (string memory) {
return "Hi";
}
}
contract GreetingImpl is SubGreeting {
function sayBye() external pure override returns (string memory) {
return "Bye";
}
}
抽象合约与虚函数的关系
需要注意,抽象合约与虚函数之间并无必要联系:
- 存在虚函数不一定就是抽象合约,这是因为
虚函数
本身是可以带有一个默认实现的,因此一个具体合约也可以带有一个虚函数,只要该虚函数有一个默认实现 - 抽象合约中也不一定有虚函数,即使所有函数都已经被具体实现,该合约仍可以被标志为抽象合约。此举旨在告知使用者不应直接实例化此合约。例如,该合约可能是一个模板合约,需要进一步继承并扩展
假设我们需要实现一批多语言的打招呼和告别的合约,合约有两个函数,sayHi
sayBye
,默认的实现是使用英文打招呼和告别:
Greeting.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
abstract contract Greeting {
// 默认实现为英文打招呼
function sayHi() external virtual returns (string memory) {
return "Hi";
}
// 默认实现为英文告别
function sayBye() external virtual returns (string memory) {
return "Bye";
}
}
该实例是虚拟合约,不能被初始化,它应该被其他具体合约继承,根据不同语言的具体合约具体地实现 sayHi
sayBye
函数。一个英文版的具体合约:
Greeting.sol
// 英文版具体合约,可以被实例化
contract EnglishGreeting is Greeting {
// 内部未重新实现 sayHi, sayBye 两个虚函数
// 但仍然是合法的,此时将使用虚函数的默认实现
}
此时我们再新增一个中文版的合约:
Greeting.sol
contract ChineseGreeting is Greeting {
function sayHi() external pure override returns (string memory) {
return unicode"你好";
}
function sayBye() external pure override returns (string memory) {
return unicode"拜拜";
}
}