Concepts / Implicit Conversion

Implicit Conversion

An implicit conversion is an automatic conversion from one type to another performed by the compiler without an explicit cast.

  • Programming

A Tempting Shortcut

Suppose a class named Vector has a constructor that accepts a single int. When you write Vector v1(7);, the program builds a Vector that holds 7 elements. Seeing this, it is natural to assume that the number 7 is simply turned into a Vector wherever a Vector is expected. Under that assumption, the statement Vector v2 = 7; should work just as well. This section examines that belief, shows why it is wrong for this class, and gives you a method for finding the exact place where a conversion is rejected.

What do you think happens?

Both statements start from the integer 7. Does Vector v2 = 7; compile, given that Vector v1(7); compiles?

  • Yes, it compiles and v2 holds 7 elements

  • No, it is a compile error

Reveal answer
Answer:

No, it is a compile error

Vector v1(7); is valid, but Vector v2 = 7; is a compile error because there is no implicit conversion from int to Vector. Being able to construct an object directly does not mean the compiler will convert values of that type implicitly.

Tracing the Two Declarations

Read the two declarations side by side. The first one asks the compiler to construct a Vector directly, using 7 as the constructor argument. The second one asks the compiler to make a Vector from the value 7 and store it in v2, with no constructor call written in an explicit form. The compiler accepts the first and rejects the second. Creating a Vector from the number 7 is a different operation from letting the compiler silently replace a 7 with a Vector.

cpp
Notes on the code
  • The first line names the construction explicitly and is accepted.
  • The second line requires the compiler to bridge an int to a Vector on its own, and it cannot do so for this class.
int 7Vector constructortakes the inttemporary Vectorholds 7 elementsv2 initializationuses the temporarypassed as argumentcreatesused in place of the int
If the compiler were allowed to use a single-argument constructor as a conversion, which steps would run, in order, for Vector v2 = 7?

The sequence above describes what a conversion would look like if it were allowed. In the Vector case from the source, the compiler does not take these steps for the copy-style declaration, so the statement is rejected. The key point is that a constructor existing for int is not enough by itself. The conversion path must also be permitted.

Direct Construction Versus Copy-Style Initialization

Direct construction and copy-style initialization can look similar, but they ask for different things. Direct construction, as in Vector v1(7);, names the constructor call through the parentheses and passes 7 as its argument. Copy-style initialization, as in Vector v2 = 7;, uses the equals sign and expects the value on the right to already be of the target type or to be converted to it. When the right side is an int and the target is a Vector, the second form requires an implicit conversion. Direct construction does not require one.

Vector v1(7)direct constructionVector v2 = 7copy-style initializationConstructor calledwith 7no conversion neededint to Vectorconversionmust be implicitCompilesvalidCompile errorno implicit conversionnextnextnextnext
How do the two forms differ in the constructor use and conversion they need, and why does only one compile for this class?

Single-Argument Constructors as Conversions

A constructor that takes exactly one parameter does more than build an object when you call it directly. It can also let the compiler create that object automatically when a value of the parameter's type appears where the new type is expected. In that case the constructor is serving as a conversion from its parameter type to its class type. The Vector constructor that accepts an int is an example: it defines a conversion from int to Vector, and whether that conversion is actually used depends on how the constructor is declared and on the context.

Implicit conversion can make code convenient, but it can also hide an unintended interpretation of a value. A conversion from double to a complex class can be useful, because it lets a plain numeric value serve as a complex number. A conversion from int to Vector is misleading, because the integer is being read as a count of elements, not as the same kind of thing a Vector is. The usefulness of a conversion depends on what the argument means for that class.

How the explicit Keyword Blocks Conversion

Marking a single-argument constructor with the explicit keyword blocks implicit use of that constructor without removing direct construction. The compiler will no longer use the constructor to bridge a mismatch between an int and a Vector in a copy-style declaration. But the direct form still works, because it names the construction explicitly and passes the constructor's argument. The source puts it this way: if the constructor is explicit, the compiler is not allowed to bridge the mismatch implicitly, while the direct form succeeds.

cpp
Notes on the code
  • The explicit keyword sits in front of the one-argument constructor declaration.
  • Removing the implicit path does not remove the direct path.
Vector v1(7)compilesVector v1(7)compilesVector v2 = 7compilesVector v2 = 7compile errorexplicit addedexplicit added
Compare the same two declarations with the Vector(int) constructor not explicit and then explicit. Which declaration changes from compiling to failing?

Deciding Whether a Constructor Should Be explicit

Whether a single-argument constructor should be explicit depends on the intended use of the class. The guidance in the source is to use explicit unless there is a good reason to allow automatic conversion. The decision turns on whether the conversion's meaning is clear to the people who use the class. If the argument naturally represents a value of the class, an implicit conversion may be reasonable. If the argument means something different, such as a count of elements in a Vector, an implicit conversion can mislead readers and should be blocked.

Is the conversionmeaning obvious tousers?Keep constructorimplicitgood reason requiredMark constructorexplicitdefault choiceyesno or unclear
Given the intended use of a single-argument constructor, which decision path leads to keeping it implicit and which leads to marking it explicit?

Locating the Failing Line

When a program does not behave as expected, the most useful question is where the actual result first departs from the expected one. For the two Vector declarations, the expected result of the second statement is a Vector holding 7 elements, because the first statement shows that a Vector can hold 7 elements. The actual result is a compile error at the assignment. The divergence occurs at the assignment, not at the constructor call. Narrowing the problem to one line is the fastest way to find the cause.

Vectortype of the new objectv2name being declared=copy-style initialization7int, not a Vector;conversion needed here
In the declaration Vector v2 = 7;, which token requires a conversion that cannot happen?

In the failing line, the expression supplies an int, but the destination is a Vector. That mismatch is the place to look. The token 7 is where the compiler would need a conversion it is not allowed to perform, so the error is reported at that assignment.

Mistakes Beginners Make with Conversions

  • Common mistake

    Assuming that any value a constructor accepts can be assigned to the class directly

    What it looks like
    Vector v2 = 7; after writing Vector v1(7);
    Why it fails

    Direct construction and implicit conversion are separate operations. Vector v1(7) names a constructor call, but the assignment form needs the compiler to make the conversion on its own, and this class does not allow that.

    Do this instead

    Write the construction directly, as in Vector v2(7);, or change the design if an implicit conversion is really intended.

  • Common mistake

    Treating Vector v2 = 7 as if it stores the number 7 in the vector

    What it looks like

    Reading the line as setting v2 to hold the value 7

    Why it fails

    The integer is being interpreted as a count of elements. That interpretation is hidden by the assignment syntax, which is why the source calls it misleading.

    Do this instead

    Use the direct form so the meaning of the argument is visible in the code.

  • Common mistake

    Removing explicit and expecting direct construction to break

    What it looks like

    Thinking explicit stops Vector v1(7); from compiling

    Why it fails

    The explicit keyword blocks implicit use of the constructor without removing direct construction.

    Do this instead

    Keep the direct form in code that uses explicit constructors.

  • Common mistake

    Marking a constructor implicit by default without asking whether the argument's meaning matches the class

Practice Predicting Declarations

MEDIUM

A class Meters has one constructor, Meters(double), that is not explicit. For each declaration, predict whether it compiles: (a) Meters m1(3.5); (b) Meters m2 = 3.5; (c) Meters m3 = 2; Then explain which of these depend on an implicit conversion from a value to Meters, and locate the exact line where a conversion would be needed.

Hints
  • Start by asking whether each declaration is direct construction or copy-style initialization.
  • A value of type int can be converted to double as part of the argument, but the question is whether a conversion from the initializer to Meters is permitted.
  • Compare your answer with the Vector example: a constructor existing for a type does not by itself settle whether the implicit path is allowed.
EASY

Explain, in one or two sentences, whether the Meters(double) constructor in the previous question should be explicit, using the test of whether the argument's meaning is clear to users of the class.

Hints
  • Think about whether a plain number reads naturally as a length in meters.

Key Takeaways

  • An implicit conversion is an automatic conversion from one type to another performed by the compiler without an explicit cast.
  • A single-argument constructor can provide a conversion from its parameter type to its class type, but being able to construct an object directly does not mean the compiler will convert values implicitly.
  • Vector v1(7); is valid, while Vector v2 = 7; is a compile error because there is no implicit conversion from int to Vector.
  • The explicit keyword blocks implicit use of a constructor without removing direct construction, and the default guidance for single-argument constructors is to use explicit unless there is a good reason to allow automatic conversion.
  • When a declaration fails, find the exact line where the expected and actual results diverge, and ask where one type is required while another is supplied.

Related concepts

More concepts starting with I