隐式 VS 显式转换
Nicolai M. Josuttis 的 C++ 标准库指出:
The C++ Standard Library by Nicolai M. Josuttis states:
两者之间存在细微差别
X x;
Y y(x) //explicit conversion
和
X x;
Y y = x; //implicit conversion
下面说:前者通过对 X 类型的显式转换创建一个 Y 类型的新对象,而后者通过使用隐式转换创建一个 Y 类型的新对象."
Following to say: "The former creates a new object of type Y by using an explicit conversion from type X, whereas the latter creates a new object of type Y by using an implicit conversion."
我猜我对显式转换和隐式转换的概念有点困惑.在这两种情况下,您都使用 X 并将其推入 Y 本身 - 一种使用 Y 的构造函数,而另一种使用赋值运算符.
I'm a little confused about the concepts of explicit vs implicit conversion I guess. In both cases you're taking an X and pushing it into a Y per se - one uses a Y's constructor and one uses the assignment operator though.
在这两种情况下处理转换的方式有什么不同,是什么使它显式/隐式,以及这与使用显式"关键字定义的类构造函数(如果有的话)有什么关系?
What's the difference in how the conversion is treated in these two cases, what makes it explicit/implicit, and how does this tie into making a class constructor defined with the "explicit" key word, if at all?
推荐答案
一个使用 Y 的构造函数,一个使用赋值运算符.
one uses a Y's constructor and one uses the assignment operator though.
不.在第二种情况下,它不是赋值,它是一个初始化,永远不会调用赋值运算符(operator=
);而是调用非explicit
单参数构造函数(接受类型X
作为参数).
Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=
) is never called; instead, a non-explicit
one-parameter constructor (that accepts the type X
as a parameter) is called.
初始化和赋值之间的区别很重要:在第一种情况下,正在创建一个新对象,它以初始化它的值开始它的生命(因此调用构造函数),而赋值发生当一个对象被分配(~复制)给一个已经存在并且已经处于确定状态的对象时.
The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.
无论如何,您编写的两种初始化形式的不同之处在于,在第一种情况下,您显式调用构造函数,因此任何构造函数都是可以接受的;在第二种情况下,您隐式调用了构造函数,因为您使用的不是经典"构造函数语法,而是初始化语法.
Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.
在这种情况下,只有未标记为 explicit
的单参数构造函数是可接受的.这样的构造函数被某些人称为转换"构造函数,因为它们涉及隐式转换.
In this case, only one-parameter constructors not marked with explicit
are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.
如指定在此其他答案中,任何未标记为 explicit
的构造函数都可以参与隐式转换,例如将传递给函数的对象转换为该函数所期望的类型.实际上,您可能会说这就是第二个示例中发生的情况:您想用 x
初始化(=使用从其他地方复制的值创建)y
,但是 x
首先必须转换为 Y
类型,这是通过隐式构造函数完成的.
As specified in this other answer, any constructor not marked as explicit
can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y
with x
, but x
first has to be converted to type Y
, which is done with the implicit constructor.
这种隐式转换通常是可取的:例如考虑一个字符串类,它具有来自 const char *
的转换(即非explicit
)构造函数:任何接收 string
参数的函数也可以用普通"C 字符串调用:由于转换构造函数,调用者将使用 C 字符串,被调用者将收到其 string
对象.
This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit
) constructor from a const char *
: any function that receives a string
parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string
object.
不过,在某些情况下,单参数构造函数可能不适合转换:通常,当它们的唯一参数在概念上没有转换"为正在创建的对象的类型时,通常会发生这种情况,但它只是构造的一个参数;例如考虑一个文件流对象:可能它会有一个构造函数来接受要打开的文件的名称,但是说这样的字符串被转换"为适用于该文件的流是没有意义的.
Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.
您还可以找到一些更复杂的场景,在这些场景中,这些隐式转换会完全破坏程序员对重载解析所期望的行为;这方面的例子可以在我上面链接的答案下面找到.
You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.
更简单地说,某些构造函数可能非常重量级,因此类设计者可能希望确保显式调用它们.在这些情况下,构造函数被标记为 explicit
,因此它只能在显式作为构造函数"调用时使用,并且不参与隐式转换.
More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit
, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.
相关文章