What is a converting constructor in C++ ? What is it for?
Asked Answered
V

3

64

I have heard that C++ has something called "conversion constructors" or "converting constructors". What are these, and what are they for? I saw it mentioned with regards to this code:

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

 int main()
{
    MyClass M = 1 ;
}
Vickivickie answered 25/2, 2013 at 22:9 Comment(0)
W
77

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.

Wellintentioned answered 25/2, 2013 at 22:31 Comment(0)
V
24

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.

Vickivickie answered 25/2, 2013 at 22:9 Comment(8)
The third constructor in the first example isn't a copy constructor. A copy constructors argument has to be one of: X&, const X&, volatile X&, or const volatile X&.Wellintentioned
You can just write MyClass M(1); etc. in the last example. Careful with those multicharacter literals as well.Sundries
Did you even bother compiling the code before posting it? Your strings are actually multicharacter constants, and do not implicitly convert to char const *!Measly
I also don't think that a constructor needs to have one argument to be a converting constructor. It just needs to be non-explicit: "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."Wellintentioned
Actually, in C++03 it must have a single parameter. In C++11 it can have any amount. This is to make room for conversions from a braced-init-list.Wellintentioned
"A constructor that can be called with a single argument is used for conversions from the type of the argument to the class type. Such a constructor is called a conversion constructor." comes from msdn.microsoft.com/en-us/library/s2ff0fz8(v=vs.80).aspx. OK for difference C++03 / C++11Vickivickie
@MooingDuck It says "can be called with a single parameter" - basically the same thing.Wellintentioned
Thank you for not writing, as so many on the web have done, "Easy: implicit conversions don't use the keyword explicit" and then dusting your hands with the satisfaction of a job well done. Regardless of the faults others have complained of, this answer is straightforward without being self-referential.Treat
M
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.

Messier answered 12/1, 2019 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.