Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 ; } 
like image 302
kiriloff Avatar asked Feb 25 '13 22:02

kiriloff


People also ask

What is a converting constructor?

A constructor that is not declared with the specifier explicit and which can be called with a single parameter (until C++11) is called a converting constructor.

Why do we use conversion constructors?

Sometimes constructors may take some arguments, or sometimes it does not take arguments. When a constructor takes only one argument then this type of constructors becomes conversion constructor. This type of constructor allows automatic conversion to the class being constructed.

Why do we use conversion constructors in C++?

In C++, if a class has a constructor which can be called with a single argument, then this constructor becomes conversion constructor because such a constructor allows automatic conversion to the class being constructed.

What is the purpose of a constructor in C?

A Constructor in C is used in the memory management of C++programming. It allows built-in data types like int, float and user-defined data types such as class. Constructor in Object-oriented programming initializes the variable of a user-defined data type. Constructor helps in the creation of an object.


2 Answers

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.

like image 80
Joseph Mansfield Avatar answered Oct 02 '22 00:10

Joseph Mansfield


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.

like image 24
kiriloff Avatar answered Oct 02 '22 02:10

kiriloff