合约继承子合约包含构造函数时报错
错误信息
在写了一个业务合约时,发现被继承合约含有构造函数时报错,去掉被继承合约中构造函数正常,有些奇怪,于是写一个简单例子进行复现,合约代码如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
//基合约接囗
interface IcontractA {
function getMsg() external view returns(string memory);
}
//基合约实现
contract contractA is IcontractA {
string message;
//构造函数
constructor(string memory _message) {
message = _message;
}
function _getMsg() internal view returns (string memory) {
return message;
}
function getMsg() external override view returns(string memory) {
return _getMsg();
}
}
//子合约 - 继承基合约
contract contractB is contractA {
address admin;
//构造函数
constructor(string memory _message) {
admin = msg.sender;
}
//调用基合约函数
function callA() external view returns(string memory) {
return _getMsg();
}
}
错误信息
TypeError: Contract "contractB" should be marked as abstract. --> Test/CallContract.sol:28:1: | 28 | contract contractB is contractA { | ^ (Relevant source part starts here and spans across multiple lines). Note: Missing implementation: --> Test/CallContract.sol:14:5: | 14 | constructor(string memory _message) { | ^ (Relevant source part starts here and spans across multiple lines).
Remix浏览器执行结果:

原因
当继承合约时,派生合约(子合约)需要提供基类构造函数需要的所有参数,参见 合约 — Solidity develop 文档
解决方案
在派生合约构造函数中添加基合约所需要的参数
32行调整如下:
constructor(string memory _message) contractA(_message) {
修正后合约代码如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
//基合约接囗
interface IcontractA {
function getMsg() external view returns(string memory);
}
//基合约实现
contract contractA is IcontractA {
string message;
//构造函数
constructor(string memory _message) {
message = _message;
}
function _getMsg() internal view returns (string memory) {
return message;
}
function getMsg() external override view returns(string memory) {
return _getMsg();
}
}
//子合约 - 继承基合约
contract contractB is contractA {
address admin;
//构造函数
constructor(string memory _message) contractA(_message) {
admin = msg.sender;
}
//调用基合约函数
function callA() external view returns(string memory) {
return _getMsg();
}
}
如果基合约构造函数无参数,在派生合约中也需要提供基合约构造函数,只是无参而已,微调上面代码,基合约构造函数设置无参
32行调整如下:
constructor(string memory _message) contractA() {
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
//基合约接囗
interface IcontractA {
function getMsg() external view returns(string memory);
}
//基合约实现
contract contractA is IcontractA {
string message;
//构造函数
constructor() {
message = "_message";
}
function _getMsg() internal view returns (string memory) {
return message;
}
function getMsg() external override view returns(string memory) {
return _getMsg();
}
}
//子合约 - 继承基合约
contract contractB is contractA {
address admin;
//构造函数
constructor() contractA() {
admin = msg.sender;
}
//调用基合约函数
function callA() external view returns(string memory) {
return _getMsg();
}
}
合约B中创建另一个合约A,调用合约A中view函数时,不能使用view
当子合约中创建一个基合约,通过新创建的基合约调用自己的查询函数(使用view修饰符)时,子合约中的函数不能使用view修饰符,合约代码如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
//基合约接囗
interface IcontractA {
function getMsg() external view returns(string memory);
}
//基合约实现
contract contractA is IcontractA {
string message;
//构造函数
constructor(string memory _message) {
message = _message;
}
function _getMsg() internal view returns (string memory) {
return message;
}
function getMsg() external override view returns (string memory) {
return _getMsg();
}
}
//子合约 - 继承基合约
contract contractB is contractA {
address admin;
//构造函数
constructor(string memory _message) contractA(_message) {
admin = msg.sender;
}
//调用基合约函数
function callA() external view returns (string memory) {
return _getMsg();
}
//创建基合约,调用函数
function callANewContract() external view returns (string memory) {
contractA contractAddr = new contractA("Hello, I am tracy");
return contractA(contractAddr).getMsg();
}
}
错误信息如下:
TypeError: Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable. --> Test/CallContract.sol:43:34: | 43 | contractA contractAddr = new contractA("Hello, I am tracy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

去除42行中的view修饰符,部署合约B,发现调用函数callANewContract()居然是收取gas费的函数(黄色背景标识为收取gas费函数),如下图所示:

本文详细介绍了在Solidity中遇到的合约继承时构造函数报错的问题,以及解决方法。当子合约继承含有构造函数的基合约时,必须在子合约构造函数中调用基合约的构造函数并传入相应参数。此外,还讨论了子合约内部创建基合约实例并调用其view函数会消耗gas的情况,并提供了相应的代码示例和错误分析。

193

被折叠的 条评论
为什么被折叠?



