隐式与显式转换 Nicolai M. Josuttis的C++标准库:

隐式与显式转换 Nicolai M. Josuttis的C++标准库:,c++,type-conversion,C++,Type Conversion,两者之间有细微的区别 X x; Y y(x) //explicit conversion 及 下面说:“前者通过使用类型X的显式转换来创建类型Y的新对象,而后者通过使用隐式转换来创建类型Y的新对象。” 我对显式转换和隐式转换的概念有点困惑。在这两种情况下,你都是取一个X并把它推到一个Y中——一个使用Y的构造函数,另一个使用赋值操作符 在这两种情况下处理转换的方式有什么不同,是什么使转换显式/隐式,以及这与使用“explicit”关键字定义类构造函数(如果有的话)有什么联系?第一种形式是直接初始

两者之间有细微的区别

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

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

我对显式转换和隐式转换的概念有点困惑。在这两种情况下,你都是取一个X并把它推到一个Y中——一个使用Y的构造函数,另一个使用赋值操作符

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

第一种形式是直接初始化。第二个是复制初始化

复制初始化隐式调用转换构造函数或转换运算符,然后显式调用复制构造函数(复制构造函数调用可以省略,但仍必须执行可访问性检查)

考虑第三种可能性,即复制初始化,但转换是明确的:

Y y = Y(x);

不过,我们可以使用赋值运算符

不,没有。它直接调用构造函数

一个是显式的,另一个是隐式的,这是因为隐式转换可以在您不希望的情况下发生。显式的不能。最简单的例子就是布尔

假设你发明了某种类型,它可以是真的,也可以是假的,比如指针。然后让我们进一步说,为了让用户的生活更轻松,您决定让它隐式地转换为bool。这是伟大的-直到你的一个用户做了一些愚蠢的事情

int i = 0;
i = i >> MyUDT();
哦,等等,为什么还要编译呢?你根本不能移动一个MyUDT!它之所以编译,是因为
bool
是一个整数类型。编译器隐式地将其转换为bool,然后再转换为可以移位的内容。上面的代码非常愚蠢——我们只希望人们能够转换成bool,而不是bool和bool可能想做的任何事情

这就是为什么C++0x中添加了显式转换运算符

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

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

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

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

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

按照规定,任何未标记为显式的构造函数都可以参与隐式转换,例如,将传递给函数的对象转换为该函数预期的类型。实际上,您可能会说在第二个示例中就是这样:您希望使用
x
初始化(=使用从别处复制的值创建)
y
,但是
x
首先必须转换为
y
类型,这是通过隐式构造函数完成的

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

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

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


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

隐式转换不需要任何转换操作符。将数据从较小的整数类型转换为较大的整数类型或将派生类型转换为基类型时,通常使用此转换

int-iVal=100; 双dVal=iVal

与隐式转换运算符相比,显式转换构造函数更受欢迎,因为在后一种情况下,会对复制构造函数进行额外调用。

poss
Y y = (Y)x;
int i = 0;
i = i >> MyUDT();