13.14 — Converting constructors, explicit, and delete

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

Although function printFraction() 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 initializing printFraction() parameter f using the Fraction(int, int) constructor.

Consequently, the above program prints:


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. Similarly, a call to printString(‘x’) causes an implicit conversion that results in the same issue.

One way to address this issue is to make constructors (and conversion functions) explicit via the explicit keyword, which is placed in front of the function’s name. Constructors and conversion functions made explicit will not be used for implicit conversions or copy initialization:

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 and user-defined conversion member functions explicit to prevent implicit conversion errors

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.

13.15 -- Overloading the assignment operator
13.13 -- Copy initialization

119 comments to 13.14 — Converting constructors, explicit, and delete

  • Andreas Krug

    Please put  Rule: Consider making your constructors and user-defined conversion member functions explicit to prevent implicit conversion errors.  in a beautiful green box.

  • A very good beginner-friendly game development book seems to be "SFML Blueprints". You can access it for $10/month on I say "seems" because I'm just getting into the 2nd chapter. I had a bad experience with another book called "SFML Development by Example" that started well but then went into complexity-land assuming the reader is thinking about every angle of the examples...

    Anyway, this first example of Chapter 2 uses "operator=" & "=delete" :) This is a good way to see it function in the real-world.

    Also the author builds the classes first in the main.cpp just like to easily "connect-the-dots".

    Quote from book...
    "= delete is a C++11 feature that allows us to explicitly delete a special member function such as constructor, move constructor, copy constructor, copy-assignment operator, move copy-assignment operator, and destructor. It tells to the compiler to not build the default function. In this particular case, it makes the class noncopyable. Another solution would be to extend the class from sf::NonCopyable.

    = default is also possible to explicitly tell the compiler to build the default version of this member function. It could, for example, be used to define a custom constructor and a default constructor."

  • Saurabh

    Dear Nascar,
    I checked below code with C++14 using -fno-elide-constructors option.

    1.) A ob = 1; // calls 1 arg ctor and copy ctor even though copy ctor is explicit.
    2.) A obj = A{65}; // fails to compile. If explicit keyword is removed then compiles and it also calls 1 arg ctor and Copy ctor.
    3.) A ob2 = {5}; // Why it does not call copy ctor as previous? It directly invokes 1 arg ctor.

    If #1 works then why does #2 not work with explicit Copy Constructor.
    Second why #3 does not invoke Copy constructor.
    Please clarify my above doubts.

    • nascardriver

      If you want to use an old standard, you'll have to look up how things work yourself or wait for someone else to come by and explain it to you.

      Since C++17, all 3 instantiations invoke only `A(int)`.

      • Saurabh

        Yes I agree "Since C++17, all 3 instantiations invoke only `A(int)`"

        I was just confused by the difference in behavior of #1 and #2 until C++14.
        As per my understanding both will use the same mechanism
        create a temporary object using 1 arg ctor -> use this temporary object to create actual object using copy ctor.

        I was just trying to relate things with older versions.

        • nascardriver

          Bullet point 3.
          `A` is a class-type. `3` is not `A`. `A(int)` is used for conversion. The result of `A(int)` is used to direct-initialize `ob`.

          Since C++17, bullet point 1 is used.

  • Zuhail

    Please answer me , why the call to the given fnctn doesnt work? I've added appropriate comment for the query

    • nascardriver

      There can be at most 1 user-defined conversion per argument when you call a function.
      `show_1(10)` works, because int->Pet is only 1 conversion.
      `show_1("Toffee")` doesn't work, because `const char[7] -> std::string -> Pet` are 2 conversions.

      You can use list-initialization to explicitly construct a `Pet` during the call to `show_1`

  • topherno

    Hey Alex,

    Regarding prevention of implicit conversions via explicit, why on earth is "Direct or uniform initialization will also still convert parameters to match" still allowed? I tested it out with clang, and it's true. Because as a result, explicit only prevents implicit conversions some of the time, and all you have to do to unwittingly get around it is use either direct or uniform initialization. And uniform initialization is even what we're supposed to be using when writing modern C++ code. Am I missing something or is this some known shortcoming that's going to be addressed in future C++ versions? Thanks.

    • nascardriver

      This lesson kind of misses the point of `explicit`, or rather, when copy initialization happens. `explicit` is there to prevent you from constructing a type when you didn't mean to, for example

      Parameters are initialized with copy-initialization. `std::vector`'s size constructor is `explicit`, so this code won't compile. If `std::vector`'s size constructor wasn't `explicit`, the above code would construct a vector with 123 elements, which is very not obvious and probably not intended from the call in `main`. `explicit` forces the developer to be explicit when they really want to create a large `std::vector` in `main`'s call.

      Whenever a constructor does something unexpected, it should be `explicit` to prevent accidentally constructing an object in a function call. Some types don't need `explicit` constructors, because they do exactly what would be expected, eg.

  • Passionate_programmer

    Can we prevent 'elision' in copy constructors from happening by putting 'explicit' or 'delete' keyword in front of copy constructor even in C++17? In other words, If I wanted the code below call both default and copy constructors, what should I do in C++17?

    >>One way to address this issue is to make constructors (and conversion functions) explicit via the explicit keyword
    What kind of functions are 'conversion functions'? Like 'operator typecast'?

    • nascardriver

      You can't prevent this kind of copy elision. It's a mandatory optimization.

      > What kind of functions are 'conversion functions'? Like 'operator typecast'?
      Yes, typecast operators

    • Fan

      More info here:


      Under the following circumstances, ... The copy/move constructors need not be present or accessible:

      * ...

      * In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

      ... (Your example fits here)

  • Rushhahb

    >>Because Fraction has a constructor willing to take a single integer, the compiler will implicitly convert the literal 6 into a Fraction object.

    Does the sentence above imply that this constructor conversion feature works in this situation because we have default parameters (0,1) for the constructor? I didn't get the part that says 'Because Fraction has a constructor willing to take a single integer'!

    >>It does this by initializing printFraction() parameter f using the Fraction(int, int) constructor.
    Do we have initialization here because of having pass by reference not by value?

    • nascardriver

      It works because we have a constructor that works with 1 argument. It doesn't matter if that constructor exists because there's one with default arguments or because we have a constructor with 1 parameter that isn't defaulted.

      We have initialization here, because `printFraction` wants a `Fraction` but we're giving it an `int`. The `int` is used to construct a temporary `Fraction`.

  • Mariam

    MyString(char) = delete;

    If any use of this constructor causes compile errors, can we say that this line of code is unnecessary?
    Why this constructor exist at all?

    • nascardriver

      Without deleting this constructor,

      would call `MyString(int)` (`char` is an integral type and can be converted to `int`).
      By adding `MyString(char)`, `mine` tries to call `MyString(char)` instead (Because it's a better match than `MyString(int)`).

  • robinchaz

    Why does this not invoke copy constructor for me? Is it because of copy elision?

    or originally char 'x' is converted to a temporary Mystring object and mine is copy constructed through the temporary object, but there is copy elision and instead mine will be directly initialized by 'x'

    • nascardriver

      That comment was wrong. The copy constructor isn't used in this example.

      • robinchaz

        but without copy elision my comment about the or..... is correct?

        • nascardriver

          Initialization only uses the copy constructor if you're using another named object to initialize. Temporaries don't invoke the copy constructor.

  • salah


    Why this code compiled? I used explicit keyword to disallow the constructor to convert any implicit conversion!.

  • Al

    When you say "Consider making your [...] user-defined conversion member functions explicit to prevent implicit conversion errors" do you mean when overloading the typecast as a member function? You're saying to consider using `explicit` in cases like the following, right?

    If that's not the case, what do you mean by "conversion member FUNCTIONS"?

  • Kwonk

    Hi, in the last lesson I asked:


    Does that mean

    is the same as


    is the same as


    You replied by saying that explicit constructors prevent this example.
    But let's say none of the constructors used are marked as explicit. With this in mind, does that mean intializing an object via the copy constructor or via implicit conversion is treated the same way when you use the copy initialization syntax instead of the uniform/direct initialization syntax?

    • nascardriver

      I don't think there's a difference. That doesn't mean there isn't a difference, but I know how

      would do something different than

      Same for the `otherFraction` example.

  • kavin

    Hi, under 'The explicit keyword' line 14,

    why have you used a pointer type as a parameter ? Can't we just use (const std::string string) as parameter ? Is there any advantage of using a pointer type over std::string type ?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]