The C++ Standard Library by Nicolai M. Josuttis states:
There is a minor difference between
X x; Y y(x) //explicit conversion
and
X x; Y y = x; //implicit conversion
Following to say: "The former creates a new object of type Y by using an explicit conversion from type X, whereas the latter creates a new object of type Y by using an implicit conversion."
I'm a little confused about the concepts of explicit vs implicit conversion I guess. In both cases you're taking an X and pushing it into a Y per se - one uses a Y's constructor and one uses the assignment operator though.
What's the difference in how the conversion is treated in these two cases, what makes it explicit/implicit, and how does this tie into making a class constructor defined with the "explicit" key word, if at all?
Explicit type conversion, also called type casting, is a type conversion which is explicitly defined within a program (instead of being done automatically according to the rules of the language for implicit type conversion). It is defined by the user in the program.
Implicit conversions: No special syntax is required because the conversion always succeeds and no data will be lost. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
one uses a Y's constructor and one uses the assignment operator though.
Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=
) is never called; instead, a non-explicit
one-parameter constructor (that accepts the type X
as a parameter) is called.
The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.
Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.
In this case, only one-parameter constructors not marked with explicit
are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.
As specified in this other answer, any constructor not marked as explicit
can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y
with x
, but x
first has to be converted to type Y
, which is done with the implicit constructor.
This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit
) constructor from a const char *
: any function that receives a string
parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string
object.
Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.
You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.
More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit
, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With