c++ - 隐式 VS 显式转换

标签 c++ type-conversion

Nicolai M. Josuttis 的 C++ 标准库指出:

两者之间存在细微差别

X x;
Y y(x) //explicit conversion

X x;
Y y = x; //implicit conversion

下面说:“前者通过对 X 类型的显式转换创建一个 Y 类型的新对象,而后者通过使用隐式转换创建一个 Y 类型的新对象。”

我猜我对显式转换和隐式转换的概念有点困惑。在这两种情况下,您都使用 X 并将其插入 Y 本身 - 一种使用 Y 的构造函数,而另一种使用赋值运算符。

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

最佳答案

one uses a Y's constructor and one uses the assignment operator though.

不。在第二种情况下,它不是赋值,它是一个初始化,永远不会调用赋值运算符(operator=);而是调用非explicit 单参数构造函数(接受类型X 作为参数)。

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

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

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

如指定 in this other answer ,任何未标记为 explicit 的构造函数都可以参与隐式转换,例如将传递给函数的对象转换为该函数所期望的类型。实际上,您可能会说这就是第二个示例中发生的情况:您想用 x 初始化(=使用从其他地方复制的值创建)y,但是 x 首先必须转换为 Y 类型,这是通过隐式构造函数完成的。

这种隐式转换通常是可取的:例如考虑一个字符串类,它具有来自 const char * 的转换(即非explicit)构造函数:任何接收 string 参数的函数也可以用“普通”C 字符串调用:由于转换构造函数,调用者将使用 C 字符串,被调用者将收到其 string 对象。

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

您还可以找到一些更复杂的场景,在这些场景中,这些隐式转换会完全破坏程序员对重载解析所期望的行为;这方面的例子可以在我上面链接的答案下面找到。

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

关于c++ - 隐式 VS 显式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7099957/

相关文章:

c++ - 如何检查类型是否为 int 的 typedef

c++ - 将字符串指向另一个字符串指针 C++

c++ - 为什么一个编译器在类型合适的构造函数可用时尝试使用已删除的复制构造函数

c# - 在 C# 中解析十六进制字符串

c++ - typeid() 是否足以保证类型安全?

java - Java中从字符串到sql日期的日期转换给出不同的输出?

c++ - 列出目录中的文件,不是递归的,只有文件没有子目录,使用C++

c++ - 有符号整数类型的按位运算结果是否定义明确?

Golang - 将 uint 转换为 os.FileMode

c - float 到有符号整数的转换与 float 到无符号整数的转换不匹配