当合约中至少有一个函数没有被实现,
或者合约没有为其所有的基本合约构造函数提供参数时, 合约必须被标记为 abstract。
即使不是这种情况,合约仍然可以被标记为 abstract, 例如,当您不打算直接创建合约时。
抽象(abstract)合约类似于 接口(interface)合约, 但是接口(interface)合约可以声明的内容更加有限。
通俗解释
抽象合约是一种至少包含一个未被实现(即没有函数体的)函数的合约。
这种合约不能直接部署到以太坊网络上,因为它不是完整定义的。
抽象合约通常作为基础合约,为派生合约提供接口和部分实现。
派生合约需要实现所有未定义的功能,才能成为非抽象合约,从而可以部署。
使用场景
- 定义接口规范
抽象合约可以定义一组函数,这组函数必须由任何继承该合约的非抽象合约实现。
这类似于接口,但抽象合约可以包含一些已实现的函数。
- 代码复用
通过在抽象合约中实现一些通用功能,可以减少在多个合约中重复相同代码的需要。
派生合约可以继承并使用这些实现,同时提供特定的功能实现。
- 多合约系统的开发
在开发包含多个合约的复杂系统时,抽象合约可以用来定义各个组件之间的通用接口。
这有助于分离关注点,提高代码的可维护性和可扩展性。
- 强制实现模式
当你希望确保所有派生合约都遵循特定的实现模式时,抽象合约是一个有用的工具。
通过在抽象合约中声明抽象函数,你可以强制要求派生合约实现这些函数,从而遵循设计的模式。
抽象合约是Solidity和其他面向对象编程语言中常用的一种设计模式,有助于构建灵活、可扩展的智能合约应用。
抽象合约的定义通常包括使用abstract关键字,以及至少一个function声明没有具体实现(没有大括号和函数体)。
抽象合约的定义示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract AbsName {
uint256 value;
function getValue() public view returns (uint256) {
return value;
}
}
contract Name is AbsName{
}
抽象合约的实现方式
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract AbsName {
uint256 value;
function getValue() public view returns (uint256) {
return value;
}
function setValue( uint _value) public virtual;
}
contract Name is AbsName{
function setValue( uint _value) public override {
value = _value;
}
}
ERC20 实现
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
contract MyToken is ERC20, ERC20Permit {
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {
_mint(msg.sender, 1000 * (10 ** 18) );
}
}
ERC721 实现
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyToken is ERC721URIStorage {
constructor() ERC721("MyToken", "MTK") {}
function create(uint256 tokenId, string memory ur) public {
_mint(msg.sender, tokenId);
_setTokenURI(tokenId, ur);
}
}