C++ Explicit Constructor
Introduction
In C programming, we used to initialize variables using assignment operator =
and passing arguments at the right side of the assignment operator =
.
In C++ programming, this feature has been kept. However, it is not recommended to use assignment operator =
to initialize objects, especially for the objects whose constructor only takes one single argument, because it is often confusing to the readers who first read the code. For example, we initialize A
typed variable a
using A a = 1
. At first glance, the reader would wonder why an integer could be “assigned” to an A
typed variable. But actually it is calling the constructor.
Instead of using the confusing assignment operator =
, we use parentheses ()
and the more recommended curly braces {}
to. Especially for curly braces {}
, it unambiguously means that it will invoke the constructor.
In C++ programming, initialization using assignment operator =
is called implicit initialization, and initialization using parentheses ()
and curly braces {}
is called explicit initialization.
In this blog post, I will give some concrete examples of implicit initialization and explicit initialization.
Examples
We use explicit
specifier for constructor to specify that the constructor would only be invoked explicitly using parentheses ()
and curly braces {}
. The compiler will raise errors if the user tries to invoke an explicit constructor using an assignment operator =
.
1 |
|
To compile the program, please run the following command in the terminal.
1 | $ g++ explicit_constructor.cpp -o explicit_constructor -std=c++11 |
The expected output of the program would be as follows.
1 | $ ./explicit_constructor |
Parenthesis VS Braces
In some scenarios, using parenthesis ()
will have different effects from using braces {}
.
1 | // An vector of integers containing one element of 2. |
While the expressions look ambiguous to the readers, they are not ambiguous to the compiler. Using {}
automatically invokes std::initializer_list
where the corresponding constructor accepts an std::initializer_list
parameter.
Looking at the constructors for std::vector
. We do find that std::vector
has a corresponding constructor that accepts an std::initializer_list
parameter.
1 | vector( std::initializer_list<T> init, |
So this means {1, 2}
is an entirety of std::initializer_list<int>
rather than two individual int
. Therefore, std::vector<int> v2{1, 2}
constructs an vector of integers containing two elements, 1 and 2. Parenthesis ()
does not have this special effect.
In addition, using {}
will invoke implicit type conversion checking during compilation, whereas ()
has no such effect. The previous example was modified so that there will be implicit type conversion before invoking the constructor.
1 |
|
1 | $ g++ explicit_constructor.cpp -o explicit_constructor -std=c++11 |
This means when using {}
and ()
seems to be interchangeable, we should use {}
as much as possible.
Conclusions
Use explicit
specifier and {}
and ()
for initialization as much as possible and be careful about the difference between {}
and ()
when the constructor accepts an std::initializer_list
parameter presents are the best practice.
C++ Explicit Constructor