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

本小妞迷上赌 提交于 2019-12-16 22:23:53

问题


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 ;
}

回答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.




回答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.




回答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.



来源:https://stackoverflow.com/questions/15077466/what-is-a-converting-constructor-in-c-what-is-it-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!