【问题标题】:How does constructor conversion work in C++?构造函数转换如何在 C++ 中工作?
【发布时间】:2013-06-20 09:14:40
【问题描述】:
构造函数转换是如何工作的?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
产生输出
One
Two(const One&)
f(Two)
【问题讨论】:
标签:
c++
constructor
implicit-conversion
【解决方案1】:
可以使用单个参数调用的任何构造函数都被视为implicit conversion constructor。这包括简单的 1 参数情况和默认参数的使用。
在任何需要 X 并提供 Y 的上下文中都会考虑这种转换,并且 Y 具有这种隐式转换的可能性。请注意,许多其他内置转换也可以混合使用(例如调整 const-ness、integral 和 fp 提升、转换等)。规则是最多允许一个“用户定义”隐式转换在混合。
在某些情况下,这可能非常令人惊讶,因此一般建议是让任何此类 ctor explicit。该关键字使转换成为可能,但不是隐式的:您必须使用 T() 语法来强制转换。
以std::vector 为例,它有一个 ctor 采用 size_t,设置初始大小。它是明确的——否则你的foo(vector<double> const& ) 函数可能会被错误地用 foo(42) 调用。
【解决方案2】:
这是正确的结果。由于constructor 不是explicit - 隐式转换有效(这里One 隐式转换为Two)。
one 被创建,然后当传递给f 时转换为Two。
【解决方案3】:
Two(const One&) {cout<<"Two(const One&)"<<endl;} 构造函数的意思是你可以在任何时候——隐式地——从One 构造一个Two 值。当您调用 f(one) 它需要一个 Two 参数时,它会得到一个 One,因此编译器将 2 和 2 放在一起并说“我将从 One 中创建一个临时的 Two 并完成调用到f()"...每个人都会很高兴。万岁!
【解决方案4】:
编译器必须在堆栈上创建Two 实例的副本。当您调用 f() 的参数是类 One(或任何其他)的对象时,编译器会查看类 Two 的定义并尝试找到采用 One(或任何其他)对象(或引用)的构造函数作为论据。当找到这样的构造函数时,它会使用它构造对象。之所以称为隐式,是因为编译器会在没有您干预的情况下执行此操作。
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
输出将是:
Foo(整数)
f(Foo)