什么是C ++中的转换构造函数? 这是为了什么?

我听说C ++有一些名为“转换构造函数”或“转换构造函数”的东西。 这些是什么,它们是什么? 我看到它提到这个代码:

class MyClass { public: int a, b; MyClass( int i ) {} } int main() { MyClass M = 1 ; } 

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

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

  • C ++ 03 :§12.3.1

    一个声明了没有函数说明符 explicit构造函数可以用一个参数来调用,它指定了从第一个参数types到它的types的转换。 这样的构造函数被称为转换构造函数。

  • C ++ 11 :§12.3.1

    没有explicit声明的构造函数指定了从其参数types到其类的types的转换。 这样的构造函数被称为转换构造函数。

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

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

将返回值指定为braced-init-list的能力被认为是一种转换。 这使用foo的转换构造函数,它接受一个float和一个int 。 另外,我们可以通过bar({2.5f, 10})来调用这个函数。 这也是一个转换。 由于它们是转换,所以它们用于转换构造函数的构造函数是有意义的。

因此,需要注意的是,使得具有floatintfoo的构造函数具有explicit函数说明符将停止编译上述代码。 上面的新语法只有在有可用的转换构造函数时才能使用。

  • C ++ 11 :§6.6.3:

    带有braced-init-listreturn语句通过copy-list-initialization(8.5.4)从指定的初始值设定项列表中初始化要从函数返回的对象或引用。

    第8.5节:

    在parameter passing中发生的初始化称为复制初始化。

    §12.3.1:

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

用转换构造函数隐式转换

让我们来举一个更复杂的例子

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

前两个构造函数正在转换构造函数。 第三个是复制构造函数,因此它是另一个转换构造函数。

一个转换构造函数可以实现从参数types到构造函数types的隐式转换。 在这里,第一个构造函数可以从int类转换为MyClass类的对象。 第二个构造函数可以将string转换为MyClass类的对象。 第三…从类MyClass的对象到类MyClass的对象!

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

那么,在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关键字呢?

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

然后,编译器不会接受

  int main() { MyClass M = 1 ; } 

因为这是隐式转换。 相反,必须写

  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关键字总是用于防止构造函数的隐式转换,并且它适用于类声明中的构造函数。