What is a converting constructor in C++ ? What is it for?

Solution 1:

The definition for a converting constructor is different between C++03 and C++11. In both cases it must be a non-explicit constructor (otherwise it wouldn't be involved in implicit conversions), but for C++03 it must also be callable with a single argument. That is:

struct foo
{
  foo(int x);              // 1
  foo(char* s, int x = 0); // 2
  foo(float f, int x);     // 3
  explicit foo(char x);    // 4
};

Constructors 1 and 2 are both converting constructors in C++03 and C++11. Constructor 3, which must take two arguments, is only a converting constructor in C++11. The last, constructor 4, is not a converting constructor because it is explicit.

  • C++03: §12.3.1

    A constructor declared without the function-specifier explicit that can be called with a single parameter specifies a conversion from the type of its first parameter to the type of its class. Such a constructor is called a converting constructor.

  • C++11: §12.3.1

    A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

Why are constructors with more than a single parameter considered to be converting constructors in C++11? That is because the new standard provides us with some handy syntax for passing arguments and returning values using braced-init-lists. Consider the following example:

foo bar(foo f)
{
  return {1.0f, 5};
}

The ability to specify the return value as a braced-init-list is considered to be a conversion. This uses the converting constructor for foo that takes a float and an int. In addition, we can call this function by doing bar({2.5f, 10}). This is also a conversion. Since they are conversions, it makes sense for the constructors they use to be converting constructors.

It is important to note, therefore, that making the constructor of foo which takes a float and an int have the explicit function specifier would stop the above code from compiling. The above new syntax can only be used if there is a converting constructor available to do the job.

  • C++11: §6.6.3:

    A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization (8.5.4) from the specified initializer list.

    §8.5:

    The initialization that occurs [...] in argument passing [...] is called copy-initialization.

    §12.3.1:

    An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.

Solution 2:

Converting implicitly with converting constructor

Let's make the example in the question more complex

class MyClass
{
  public:
     int a, b;
     MyClass( int i ) {}
     MyClass( const char* n, int k = 0 ) {}
     MyClass( MyClass& obj ) {}
}

First two constructors are converting constructors. The third one is a copy constructor, and as such it is another converting constructor.

A converting constructor enables implicit conversion from argument type to the constructor type. Here, the first constructor enables conversion from an int to an object of class MyClass. Second constructor enables conversion from an string to an object of class MyClass. And third... from an object of class MyClass to an object of class MyClass !

To be a converting constructor, constructor must have single argument (in the second one, second argument has one default value) and be declared without keyword explicit.

Then, initialization in main can look like this:

int main()
{
    MyClass M = 1 ;
    // which is an alternative to
    MyClass M = MyClass(1) ;

    MyClass M = "super" ;
    // which is an alternative to
    MyClass M = MyClass("super", 0) ;
    // or
    MyClass M = MyClass("super") ;
}

Explicit keyword and constructors

Now, what if we had used the explicit keyword ?

class MyClass
{
  public:
     int a, b;
     explicit MyClass( int i ) {}
}

Then, compiler would not accept

   int main()
    {
        MyClass M = 1 ;
    }

since this is implicit conversion. Instead, have to write

   int main()
    {
        MyClass M(1) ;
        MyClass M = MyClass(1) ;
        MyClass* M = new MyClass(1) ;
        MyClass M = (MyClass)1;
        MyClass M = static_cast<MyClass>(1);
    }

explicit keyword is always to be used to prevent implicit conversion for a constructor and it applies to constructor in a class declaration.

Solution 3:

A conversion constructor is a single-parameter constructor that is declared without the function specifier explicit . The compiler uses conversion constructors to convert objects from the type of the first parameter to the type of the conversion constructor's class.