隐式VS显式转换

Joh*_*0te 18 c++ type-conversion

Nicolai M. Josuttis的C++标准库声明:

两者之间存在细微差别

X x;
Y y(x) //explicit conversion
Run Code Online (Sandbox Code Playgroud)

X x;
Y y = x; //implicit conversion
Run Code Online (Sandbox Code Playgroud)

接下来说:"前者通过使用类型X的显式转换创建Y类型的新对象,而后者通过使用隐式转换创建类型为Y的新对象."

我猜对于显式与隐式转换的概念我有点困惑.在这两种情况下,你都使用X并将其推入Y本身 - 一个使用Y的构造函数,一个使用赋值运算符.

在这两种情况下如何处理转换有什么不同,是什么使它显式/隐式,以及如何使用"显式"关键字定义类构造函数(如果有的话)?

Mat*_*lia 28

一个使用Y的构造函数,一个使用赋值运算符.

不.在第二种情况下,它不是赋值,它是初始化,operator=从不调用赋值运算符(); 相反,explicit调用非单参数构造函数(接受类型X作为参数).

初始化和赋值之间的区别很重要:在第一种情况下,正在创建一个新对象,它以其初始化的值开始其生命(因此调用构造函数的原因),而当一个对象发生赋值时被分配(〜复制)到已经存在已经处于确定状态的对象.

无论如何,您编写的两种初始化形式的不同之处在于,在第一种情况下,您显式调用构造函数,因此任何构造函数都是可接受的; 在第二种情况下,您隐式调用构造函数,因为您没有使用"经典"构造函数语法,而是使用初始化语法.

在这种情况下,只有未标记的单参数构造函数explicit是可接受的.这些构造函数被某些人称为"转换"构造函数,因为它们涉及隐式转换.

如此其他答案中所指定的,任何未标记为的构造函数explicit都可以参与隐式转换,例如将传递给函数的对象转换为此函数所期望的类型.其实,你可能会说,这是你的第二个例子发生了什么:你要初始化(=从其他地方复制的价值创造)yx,但x首先必须转换为类型Y,它与隐式构造函数来完成.

这种隐式转换通常是可取的:例如,对于具有转换(即非explicit)构造const char *函数的字符串类,例如:接收string参数的任何函数也可以使用"普通"C字符串调用:因为转换构造函数调用者将使用C字符串,被调用者将接收其string对象.

尽管如此,在某些情况下,单参数构造函数可能不适合转换:通常,当它们的唯一参数在概念上"转换"为正在创建的对象的类型时会发生这种情况,但它只是构造的参数; 例如关于文件流对象:可能它会有一个构造函数接受要打开的文件的名称,但是说这样的字符串被"转换"为适用于该文件的流是没有意义的.

您还可以找到一些更复杂的场景,其中这些隐式转换可以完全搞砸程序员期望从重载解析中获得的行为; 这个例子可以在我上面链接的答案中找到.

更简单地说,也可能发生一些构造函数可能非常重量级,因此类设计者可能希望确保它们被显式调用.在这些情况下,构造函数被标记为explicit,因此只有在"显式地作为构造函数"调用时才能使用它,并且不参与隐式转换.