When you are trying to compile contract with private
constructor, for example this one:
pragma solidity ^0.4.15;
contract PrivateConstructor {
string public title;
function PrivateConstructor() private {
title = "Private Constructor";
}
}
you receive this error:
TypeError: Constructor must be public or internal.
So looks like contract counstructor could be only public
or internal
.
More details here Visibility and Getters
In Solidity you specify base constructor arguments in two ways (according to http://solidity.readthedocs.io/en/latest/contracts.html#arguments-for-base-constructors):
The first way to do it is more convenient if the constructor argument is a constant and defines the behaviour of the contract or describes it. The second way has to be used if the constructor arguments of the base depend on those of the derived contract. Arguments have to be given either in the inheritance list or in modifier-style in the derived constuctor. Specifying arguments in both places is an error.
Your inheritance structure is as follows: D->C->B->A.
If we change the order a little bit (just to be sure that constructor executions are different than the code sequence) and add some logging we get:
contract A {
constructor(uint paramA) public {
log0(bytes32(0x00000000));
}
}
contract C is A(0) {
constructor(string paramC) public {
log0(bytes32(0x00000002));
}
}
contract B is A{
constructor(address paramB) public {
log0(bytes32(0x00000001));
}
}
contract D is B, C {
constructor(uint paramForA, address paramForB, string paramForC) public C(paramForC) B(paramForB)// stuff here to call A, B and C constructors with non-static parameters
{
log0(bytes32(0x00000003));
}
}
You get the following execution od constructors: A->B->C->D
Note that if you change the order of inheritance and rewrite D as follows:
contract D is C, B {
constructor(uint paramForA, address paramForB, string paramForC) public C(paramForC) B(paramForB)// stuff here to call A, B and C constructors with non-static parameters
{
log0(bytes32(0x00000003));
}
}
You will get different order of execution A->C->B->D
So the order does matter.
EDIT1:
As the above was not exactly to the point below I try to address question:
"How should contract D specify its constructor arguments for contracts A B and C to provide all required parameters and in what order? Is there only one correct order?"directly.
You can assign parameters to parent contract constructors in two ways:
1. Directly in the declaration of inheritance:
contract D is B('0x0b'), C('0x0c') {
constructor(uint paramForA, address paramForB, string paramForC) public
{
}
}
where 0x0b and 0x0a are address literals.
2. Via assigning them using syntax similar to Solidity modifiers if you want to use constructor D arguments:
contract D is B, C {
constructor(uint paramForA, address paramForB, string paramForC) public C(paramForC) B(paramForB) {}
}
There is not other way to initialize parent contract constructors that I'm aware of. If you would like to initialize state variables of parent contract you can make it within the D constructor. Those state variables has to be either public or internal in the parent contract. Hope this helps.
Best Answer
When deploy the smart contract via Remix, there's a place to input the constructor params.
If you deploy via script like hardhat, then you can pass the params via the deploy method: