Search

9.13 — Converting constructors, explicit, and delete

By default, C++ will treat any constructor as an implicit conversion operator. Consider the following case:

Although function makeNegative() is expecting a Fraction, we’ve given it the integer literal 6 instead. Because Fraction has a constructor willing to take a single integer, the compiler will implicitly convert the literal 6 into a Fraction object. It does this by copy-initializing makeNegative() parameter f using the Fraction(int, int) constructor.

Since f is already a Fraction, the return value from makeNegative() is copy-constructed back to main, which then passes it to overloaded operator<<.

Consequently, the above program prints:

Copy constructor called
-6/1

This implicit conversion works for all kinds of initialization (direct, uniform, and copy).

Constructors eligible to be used for implicit conversions are called converting constructors (or conversion constructors). Prior to C++11, only constructors taking one parameter could be converting constructors. However, with the new uniform initialization syntax in C++11, this restriction was lifted, and constructors taking multiple parameters can now be converting constructors.

The explicit keyword

While doing implicit conversions makes sense in the Fraction case, in other cases, this may be undesirable, or lead to unexpected behaviors:

In the above example, the user is trying to initialize a string with a char. Because chars are part of the integer family, the compiler will use the converting constructor MyString(int) constructor to implicitly convert the char to a MyString. The program will then print this MyString, to unexpected results.

One way to address this issue is to make constructors explicit via the explicit keyword, which is placed in front of the constructor’s name. Constructors made explicit will not be used for implicit conversions:

The above program will not compile, since MyString(int) was made explicit, and an appropriate converting constructor could not be found to implicitly convert ‘x’ to a MyString.

However, note that making a constructor explicit only prevents implicit conversions. Explicit conversions (via casting) are still allowed:

Direct or uniform initialization will also still convert parameters to match (uniform initialization will not do narrowing conversions, but it will happily do other types of conversions).

Rule: Consider making your constructors explicit to prevent implicit conversion errors

In C++11, the explicit keyword can also be used with conversion operators.

The delete keyword

In our MyString case, we really want to completely disallow ‘x’ from being converted to a MyString (whether implicit or explicit, since the results aren’t going to be intuitive). One way to partially do this is to add a MyString(char) constructor, and make it private:

However, this constructor can still be used from inside the class (private access only prevents non-members from calling this function).

A better way to resolve the issue is to use the “delete” keyword (introduced in C++11) to delete the function:

When a function has been deleted, any use of that function is considered a compile error.

Note that the copy constructor and overloaded operators may also be deleted in order to prevent those functions from being used.

9.14 -- Overloading the assignment operator
Index
9.12 -- Copy initialization

28 comments to 9.13 — Converting constructors, explicit, and delete

  • susenj

    What is the point of leaving a function with ‘delete’ when it has not to be used anywhere? In my opinion, just omit that line and it will be equivalent. Or, am I missing something here?

    • Alex

      The compiler will provide some functions by default if you do not provide them yourself (e.g. a copy constructor). This gives you a way to tell the compiler that you not only don’t want the provided function, but that any calls to such a function should be flagged as an error.

  • Miko

    Are these operator overloads correctly made?

    Visual studio doesn’t seem to care about them so I can’t test them. I tried to delete this, but code still returns what it is wanted to return.

  • Pawel

    Hi Alex,
    In the example where you use ‘explicit’ keyword for the first time, why do we get the compile error in the following line:

    I was expecting that the compiler will try to convert 5 to a MyString, which will invoke the MyString(int x) constructor. As far as I understand, the explicit keyword requires that the int is passed, so that e.g. char is not allowed. Since we’re initializing the x object with 5 (which is int), I’d expect we have a match. Could you please clarify this?

    • Alex

      Sure. Explicit means the constructor will not be used to do implicit conversions. In the code:

      Because 5 is an int and x is a MyString, the compiler will have to convert the int to a MyString. Because we haven’t requested an explicit conversion (e.g. via static_cast), the compiler will try to do an implicit conversion. Normally, it would be successful at this, because there is a MyString(int) constructor that it can use to convert an int into a MyString. However, in this case, because this constructor is marked as explicit, the compiler will exclude it for consideration when doing implicit conversions. Since the compiler won’t find any other ways to implicitly convert an int to a MyString, it will give a compile error indicating that it doesn’t know how to do the conversion.

      So, to conclude: explicit means the function will not be used for implicit conversion, but can still be used for explicit conversions.

  • loveu

    hi alex!
    why is the parameter of the constructor a char pointer?

  • Bobix Louis

    Hi Alex,
      A small doubt regarding the below behavior
      ‘However, note that making a constructor explicit only prevents implicit conversions. Explicit conversions (via direct or uniform initialization or explicit casts) are still allowed’

      Could you please help me to understand how it works? I mean, since we dont have any constructor that takes a char const(and the constructor that takes ‘int’ is already marked as explicit), how the creation of object is possible with direct or uniform initialization?

    • Alex

      I’ve updated the example a little bit to clarify better. Making a constructor only prevents implicit conversions. Explicit conversions (via casting) are allowed. Also, if you’re creating an object, the parameters passed to that object may still be converted (subject to the usual constraints, such as uniform initialization won’t do narrowing conversions).

      The compiler will happily let us do this:

      Because this isn’t an implicit conversion of a value to a MyString (which is disallowed) -- it’s an implicit conversion of char value ‘x’ to an integer, which is fine.

  • Jeffry

    HI again,  Very small thing.  I hope you don’t mind the nit-pick.   In the first example can you either add a blank line before  lines 27 and 28 or bring them out to the same indentation as line 26.   At first glance it looked like lines 26 and 27 were the body of line 26, and it was confusing.   Then I looked at line 26 and realized there was a ; at the end and no { } so then understood what was going on.  But again at first glance it didn’t seem that way.

    Thanks again for these pages, they are very helpful.

  • robbe

    Hey alex! When working with header files, where do I put the explicit keyword: in the forward declaration, the definition or both? Thanks in advance.

    • Alex

      Explicit only works with member functions, and member functions are part of classes, which don’t need forward declarations (since the definition in the class serves as the definition).

      So just put the keyword explicit inside your class definition in your header file, and you should be good to go.

  • Ramesh

    Hi Alex
    In the first program of this tutorial, i thought copy constructor is called 2 times. once at copy initialization of 6 to makenegative parameter and one more time at returning by value from makenegative function.  
    So, the statement "Copy constructor called" should be printed twice.
    But it seems copy constructor is called only once. Is my understanding wrong?

    • Alex

      Nope. When literal 6 is passed as an argument to function makeNegative, the Fraction(int, int) constructor is used to copy-initialize f directly. No copy constructor used here.

      My wording in the lesson was a little confusing on this point, so I’ve updated it to the following:

      “Although function makeNegative() is expecting a Fraction, we’ve given it the integer literal 6 instead. Because Fraction has a constructor willing to take a single integer, the compiler will implicitly convert the literal 6 into a Fraction object. It does this by copy-initializing makeNegative() parameter f using the Fraction(int, int) constructor.”

      The return value is still copy-constructed back to main().

  • dazedbrain

    typo found

    Constructors eligible to be used for implicit conversations are called converting constructors (or conversion constructors).

    do you mean implicit conversions?

  • Chris

    Hi Alex,

    at the section "The delete keyword" section you say "In our MyString case, we really want to completely disallow ‘x’ from being converted to a string (whether implicit or explicit, since the results aren’t going to be intuitive)."
    do you mean converted to an integer? since char is family integer and cannot be converted to string, i guess.

  • Sam

    I think Your explanation isn’t fully correct in the first example. Output is the following:
    Copy constructor called
    -6/1
    After looking through the debugger (I might be wrong):
    1. Because there’s a default constructor that "matches literal 6" the function call is allowed.
    2. Right after jumping to the function, default constructor is called. "f" has just been directly initialized.
    3. Copy constructor is called on the "return" statement, to evaluate it and pass back to "main" function. This anonymous object uses its overloaded operator to print its meaning.

  • Darren

    Is having the delete syntax for constructors a new(ish) thing added to c++11 (or later)? I’ve never seen it before. So instead of making the copy constructor and copy assignment operator private and not implementing them to make a class un-copyable (non-copyable?) you could just use the delete syntax instead? That is definitely more readable.

  • davidv

    Here’s a silly question.
    If we add the prototypes for the copy constructor and overloaded operator= to the private section of the class in order to prevent copying, do we actually need to write them down later, given that we’re not really planning to use them?
    Thanks.

    • By write them down, I presume you mean implement them. The answer is no, as long as you don’t call them. Don’t forget that private members can still be called by other members of the class, so you’ll have to ensure you don’t use them internally within the class. If you try to do so, you’ll get a linker error.

      • kudleep

        Hi Alex,

        can you give an example , how and in which case , one would need to use copy constructor from other class such as derived one ! The statement - “Sometimes we simply don’t want our classes to be copied at all.” , can you please explain a bit, what i understood is we don’t want compiler to provide a default copy constructor for our program.

        • I’m not sure what you mean by using copy constructors from other classes. The copy constructor is used to instantiate an object of a particular class, so the copy constructor for that class should always be used.

          As for not wanting your classes to be copied, sometimes there are legitimate reasons for this -- eg. doing an assignment would be too expensive, or you simply don’t have time to implement a deep copy and want to prevent people from accidentally using the shallow copy provided by the default copy constructor and default assignment operator the compiler provides for all classes. By making these private, we tell the compiler not to create default versions, thus circumventing the issue.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter