Solidity 构造函数
1、
constructor
: 只有在执行了构造函数后,合约代码被存入 blockchain。2、
constructor
只执行一次,在该函数内部,msg.sender 永远是部署合约的账户。单继承情况下合约的构造函数
构造函数的执行顺序,先构造 super 合约 –> sub 合约。初始化构造函数方式:
contract Base { uint x; constructor(uint x_) { x = x_; } } // Either directly specify in the inheritance list... contract Derived1 is Base(7) { constructor() {} } // or through a "modifier" of the derived constructor... contract Derived2 is Base { constructor(uint y) Base(y * y) {} } // or declare abstract... abstract contract Derived3 is Base { } // and have the next concrete derived contract initialize it. contract DerivedFromDerived is Derived3 { constructor() Base(10 + 10) {} }
需要注意,如果父合约的构造函数需要入参,子合约没有调用父合约的构造函数传递相应的参数,这个子合约就必须定义为 abstract 的。子 合约构造函数的参数列表可以是任意的,但至少得满足父合约的参数:
contract MyToken is ERC20 { string _a; constructor(string memory _name, string memory _symbol, string memory a) ERC20(_name, _symbol) { _a = a; _mint(msg.sender, 100*10**18); } function mint(address to, uint256 amount) public { _mint(to, amount); } }
MyToken
合约的构造函数有 3 个参数,前两个 _name
和 _symbol
是传给父合约的,剩下 a 可以自己使用。多继承和线性化
Solidity 的合约是支持多继承的,多继承通过要解决宝石问题。Soldility 采用了类似 Python 语言的方案。使用 C3 线性来让基类形成有向无环图(DAG Directed Acyclic Graph)。
具体来说,继承列表(is 后的)的顺序有讲究。Solidity 按照从右向左,深度优先的方法匹配父合约,直到第一个继承的合约。例如下列代码:
contract X { } contract A is X {} contract C is A, X {}
上述代码会报错线性错误,从 C 合约来看,is 后的顺序是 A, X;这表面 C 要求 X 去重写 A(从右向左解析),但是 A 是继承 X 的,它自己也需要重写 X,矛盾就出现了 (contradiction)。只需要调整 A, X 的顺序即可编译通过:
contract C is X, A {} // Correct!
最后在构造函数列表上,永远是按从左到右的方式,依次实例化:
contract Base1 { constructor() {} } contract Base2 { constructor() {} } // Constructors are executed in the following order: // 1 - Base1 // 2 - Base2 // 3 - Derived1 contract Derived1 is Base1, Base2 { constructor() Base1() Base2() {} } // Constructors are executed in the following order: // 1 - Base2 // 2 - Base1 // 3 - Derived2 contract Derived2 is Base2, Base1 { constructor() Base2() Base1() {} } // Constructors are still executed in the following order: // 1 - Base2 // 2 - Base1 // 3 - Derived3 contract Derived3 is Base2, Base1 { constructor() Base1() Base2() {} }
注意,这和继承列表的矛盾性是两码事,互不影响。