什么是 C++ 中的转换构造函数?它是做什么用的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15077466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:59:44  来源:igfitidea点击:

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

c++constructorcopy-constructor

提问by kiriloff

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:

我听说 C++ 有一种叫做“转换构造函数”或“转换构造函数”的东西。这些是什么,它们有什么用?我看到它提到了有关此代码的内容:

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

 int main()
{
    MyClass M = 1 ;
}

回答by Joseph Mansfield

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

C++03 和 C++11 之间转换构造函数的定义不同。在这两种情况下,它都必须是非explicit构造函数(否则它不会参与隐式转换),但对于 C++03,它也必须可以使用单个参数调用。那是:

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.

构造函数 1 和 2 都是转换 C++03 和 C++11 中的构造函数。必须接受两个参数的构造函数 3 只是 C++11 中的转换构造函数。最后一个构造函数 4 不是转换构造函数,因为它是explicit.

  • C++03: §12.3.1

    A constructor declared without the function-specifierexplicitthat 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-specifierexplicitspecifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

  • C++03:第 12.3.1 节

    可以使用单个参数调用的没有函数说明符声明的构造函数指定explicit从其第一个参数的类型到其类的类型的转换。这样的构造函数称为转换构造函数。

  • C++11:第 12.3.1 节

    未声明函数说明explicit符的构造函数指定从其参数类型到其类类型的转换。这样的构造函数称为转换构造函数。

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:

为什么具有多个参数的构造函数被认为是 C++11 中的转换构造函数?那是因为新标准为我们提供了一些方便的语法,用于使用braced-init-lists传递参数和返回值。考虑以下示例:

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

The ability to specify the return value as a braced-init-listis considered to be a conversion. This uses the converting constructor for foothat takes a floatand 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.

将返回值指定为花括号初始化列表的能力被认为是一种转换。这使用转换构造函数来foo获取 afloat和 an int。此外,我们可以通过执行调用此函数bar({2.5f, 10})。这也是一种转换。由于它们是转换,因此它们用于转换构造函数的构造函数是有意义的。

It is important to note, therefore, that making the constructor of foowhich takes a floatand an inthave the explicitfunction 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.

因此,重要的是要注意,使foo带有 afloat和 an的构造函数int具有explicit函数说明符会阻止上述代码的编译。上面的新语法只有在有一个转换构造函数可用于完成这项工作时才能使用。

  • C++11: §6.6.3:

    A returnstatement with a braced-init-listinitializes 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.

  • C++11:第 6.6.3 节:

    return与语句支撑-INIT列表初始化对象或参考以从功能通过复制列表的初始化(8.5.4)从指定的初始化列表返回。

    §8.5:

    在参数传递 [...] 中发生的初始化称为复制初始化。

    §12.3.1:

    显式构造函数像非显式构造函数一样构造对象,但仅在显式使用直接初始化语法 (8.5) 或强制转换 (5.2.9, 5.4) 的情况下才会这样做。

回答by kiriloff

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 intto 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 MyClassto an object of class MyClass!

转换构造函数支持从参数类型到构造函数类型的隐式转换。在这里,第一个构造函数允许从 an 转换int为 class 的对象MyClass。第二个构造函数可以将字符串转换为 class 的对象MyClass。第三...从类MyClass的对象到类的对象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.

要成为转换构造函数,构造函数必须具有单个参数(在第二个参数中,第二个参数具有一个默认值)并且声明时不带关键字explicit

Then, initialization in main can look like this:

然后,main 中的初始化看起来像这样:

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 explicitkeyword ?

现在,如果我们使用了explicit关键字呢?

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

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

explicit关键字始终用于防止构造函数的隐式转换,它适用于类声明中的构造函数。

回答by Fazail awan

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.

转换构造函数是一个单参数构造函数,它在声明时没有使用函数说明符 explicit 。编译器使用转换构造函数将对象从第一个参数的类型转换为转换构造函数的类的类型。