抽象合约(abstract contract)
前文在讲合约继承
的基类构造函数的参数
时,有提到抽象合约
,也就是说,如果派生合约
未能给其继承的基合约
指定构造函数参数时,那么,该派生合约
必须声明为抽象合约(abstract contract)
。
我们知道Java
中抽象类
的定义,其一抽象类
不能实例化,其二是
抽象类中可以拥有 抽象方法
(是一种没有方法体的、只有方法签名的方法。)
而在 Solidity 中的抽象合约
与Java
的抽象类
有异曲同工之妙。即假使合约中至少有一个函数没有实现(没有方法体,只有方法签名的方法),那么便将该合约定义为抽象合约(abstract contract)
。当然咯,前文说到继承
提到的,派生合约
未能给其基合约
的构造函数传递指定参数,这时,该合约便只能声明为抽象
的。
在 Solidity 0.8.x版本以上,抽象合约
的抽象函数
需加上virtual
修饰,而对于的派生合约中的函数实现也得加上override
修饰,否则编译过不了。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
//base contract
abstract contract Animal {
function eat() virtual public ;
}
contract Bird is Animal {
function eat() override public {
}
}
假使派生合约
未能给定所有基类的制定参数(基类构造函数的参数),那该合约也必须声明为抽象
的。
解决上图所出现的问题,有两种方式,要么派生合约
contract Snake
给定所有基类构造函数的制定参数;要么将派生合约
Snake
声明为抽象(abstract)
的。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
//base contract
contract Animal {
string public name;
constructor(string memory _name){
name = _name;
}
}
//爬行动物是动物
contract Reptile {
string public Rname;
constructor(string memory _name){
Rname = _name;
}
}
abstract contract Snake is Reptile,Animal {
//这是一只眼镜蛇 多个基类使用空格隔开
constructor() Animal("cobra"){}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
//base contract
contract Animal {
string public name;
constructor(string memory _name){
name = _name;
}
}
//爬行动物是动物
contract Reptile {
string public Rname;
constructor(string memory _name){
Rname = _name;
}
}
contract Snake is Reptile,Animal {
//这是一只眼镜蛇 多个基类使用空格隔开
constructor() Reptile("diba") Animal("cobra"){}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
//base contract
contract Animal {
string public name;
constructor(string memory _name){
name = _name;
}
}
//爬行动物是动物
contract Reptile {
string public Rname;
constructor(string memory _name){
Rname = _name;
}
}
contract Snake is Reptile,Animal {
//这是一只眼镜蛇 多个基类使用空格隔开
constructor() Reptile("diba") Animal("cobra"){}
}
若派生合约
继承自抽象合约
,而并没有去实现抽象合约
中的抽象函数
,那么,该合约依然需要标记为抽象(abstract)
的。
抽象合约将合约的定义与其实现脱钩,从而提供了更好的可扩展性和自文档性,并消除了代码重复。