25

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?

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • possible duplicate of [initialization: parenthesis vs. equals sign](http://stackoverflow.com/questions/4470553/initialization-parenthesis-vs-equals-sign) – Cheers and hth. - Alf Aug 17 '11 at 21:53
  • possible duplicate of [Is there a difference in C++ between copy initialization and direct initialization?](http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy-initialization-and-direct-initializatio) – Ben Voigt Aug 17 '11 at 21:54
  • 2
    note that both cases just invoke constructors, the "=" is not an assignment operator in this case, it's part of declaration syntx – Cheers and hth. - Alf Aug 17 '11 at 21:54
  • 1
    This should not be closed. He made a mistake- but it's *not* about the difference, it's about implicit vs explicit. – Puppy Aug 17 '11 at 21:56

4 Answers4

34

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.

Community
  • 1
  • 1
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
4

The first form is direct initialization. The second is copy initialization.

Copy initialization implicitly calls a converting constructor or conversion operator and then explicitly calls a copy constructor (the copy constructor call may be elided, but an accessibility check must still be performed).

Consider a third possibility, which is copy-initialization, but the conversion is explicit:

Y y = Y(x);

or

Y y = (Y)x;
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Can you provide a little more detail? When you say implicitly calls converting constructor, do you mean like a template constructor like the STL would use to provide implicit type conversion? And again what makes it implicit/explicit - you used the terms that are confusing me in the answer. Thank you though, I see you're on the right lines I just need it dumbed down a little. – John Humphreys Aug 17 '11 at 21:58
  • 3
    @w00te: An implicit conversion is one that the compiler adds in order to match types. An explicit conversion exists when you use cast syntax (including a functional cast, which looks like a constructor call). In the first case, you've got an explicit constructor call (the arguments are inside parentheses, it looks like a function call). In the second case, the copy constructor call is considered explicit, but the argument needs to be coerced to the correct type, and since you didn't put a cast in the source code, that coercion is implicit. – Ben Voigt Aug 17 '11 at 22:02
  • 1
    Simply: Explicit means you requested the conversion. Implicit means you didn't request the conversion, it got added because of something else your code asked to do. – Ben Voigt Aug 17 '11 at 22:03
  • Thanks for the extra detail, that clears up a lot. Upped the votes on the comment/solution since they helped. :) – John Humphreys Aug 17 '11 at 22:06
4

one uses the assignment operator though

No, it does not. It calls the constructor directly.

The reason why one is explicit and one is implicit is because implicit conversions can happen when you don't want them to. Explicit ones cannot. The easiest example of this is bool.

Let's say that you invent some type which can be either true or false- like a pointer. Then let's further say that you decide that in order to make life easier for your users, you let it convert to bool implicitly. This is great- right up until the point where one of your users does something dumb.

int i = 0;
i = i >> MyUDT();

Oh wait- why does that even compile? You can't shift a MyUDT at all! It compiles because bool is an integral type. The compiler implicitly converted it to a bool, and then to something that can be shifted. The above code is blatantly dumb- we only want people to be able to convert to a bool, not a bool and anything else that a bool might want to do.

This is why explicit conversion operators were added to C++0x.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

The Implicit casting doesn't require any casting operator. This casting is normally used when converting data from smaller integral types to larger or derived types to the base type.

int iVal = 100; double dVal = iVal;

The explicit converting constructor is preferred to the implicit conversion operator because in the latter case there is an additional call to the copy constructor.Implicit and Explicit converstions