提问人:kiriloff 提问时间:2/26/2013 最后编辑:Mooing Duckkiriloff 更新时间:1/12/2019 访问量:52310
什么是 C++ 中的转换构造函数?它是干什么用的?
What is a converting constructor in C++ ? What is it for?
问:
我听说C++有一种叫做“转换构造函数”或“转换构造函数”的东西。这些是什么,它们的用途是什么?我看到它提到了这段代码:
class MyClass
{
public:
int a, b;
MyClass( int i ) {}
}
int main()
{
MyClass M = 1 ;
}
答:
使用转换构造函数隐式转换
让我们使问题中的示例更加复杂
class MyClass
{
public:
int a, b;
MyClass( int i ) {}
MyClass( const char* n, int k = 0 ) {}
MyClass( MyClass& obj ) {}
}
前两个构造函数是转换构造函数。第三个是复制构造函数,因此它是另一个转换构造函数。
转换构造函数支持从参数类型到构造函数类型的隐式转换。在这里,第一个构造函数允许从类的对象转换为对象。第二个构造函数允许从字符串转换为类的对象。第三...从类的对象到类的对象!int
MyClass
MyClass
MyClass
MyClass
要成为转换构造函数,构造函数必须具有单个参数(在第二个参数中,第二个参数具有一个默认值)并且声明时不带关键字。explicit
然后,main 中的初始化可以如下所示:
int main()
{
MyClass M = 1 ;
// which is an alternative to
MyClass M = MyClass(1) ;
MyClass M = "super" ;
// which is an alternative to
MyClass M = MyClass("super", 0) ;
// or
MyClass M = MyClass("super") ;
}
显式关键字和构造函数
现在,如果我们使用了关键字呢?explicit
class MyClass
{
public:
int a, b;
explicit MyClass( int i ) {}
}
然后,编译器将不接受
int main()
{
MyClass M = 1 ;
}
因为这是隐式转换。相反,必须写
int main()
{
MyClass M(1) ;
MyClass M = MyClass(1) ;
MyClass* M = new MyClass(1) ;
MyClass M = (MyClass)1;
MyClass M = static_cast<MyClass>(1);
}
explicit
关键字始终用于防止构造函数的隐式转换,它适用于类声明中的构造函数。
评论
X&
const X&
volatile X&
const volatile X&
MyClass M(1);
char const *
explicit
转换构造函数的定义在 C++03 和 C++11 之间是不同的。在这两种情况下,它都必须是非构造函数(否则它不会参与隐式转换),但对于 C++03,它也必须可以使用单个参数调用。那是:explicit
struct foo
{
foo(int x); // 1
foo(char* s, int x = 0); // 2
foo(float f, int x); // 3
explicit foo(char x); // 4
};
构造函数 1 和 2 都是 C++03 和 C++11 中的转换构造函数。构造函数 3 必须接受两个参数,在 C++11 中只是一个转换构造函数。最后一个构造函数 4 不是转换构造函数,因为它是 .explicit
C++03:§12.3.1
一个声明的不带函数说明符的构造函数,可以使用单个参数调用,它指定从其第一个参数的类型到其类类型的转换。这种构造函数称为转换构造函数。
explicit
C++11:§12.3.1
不带函数说明符的构造函数指定从其参数类型到其类类型的转换。这种构造函数称为转换构造函数。
explicit
为什么具有多个参数的构造函数被视为 C++11 中的转换构造函数?这是因为新标准为我们提供了一些方便的语法,用于使用 braced-init-lists 传递参数和返回值。请看以下示例:
foo bar(foo f)
{
return {1.0f, 5};
}
将返回值指定为 braced-init-list 的能力被视为转换。这使用转换构造函数,因为它需要 a 和 an .此外,我们可以通过执行 .这也是一种转换。由于它们是转换,因此它们用于转换构造函数的构造函数是有意义的。foo
float
int
bar({2.5f, 10})
因此,需要注意的是,让 which 的构造函数 takes a 和 an have 函数说明符会阻止上述代码的编译。仅当有可用于执行该工作的转换构造函数时,才能使用上述新语法。foo
float
int
explicit
C++ 11: §6.6.3:
带有 braced-init-list 的语句通过 copy-list-initialization (8.5.4) 从指定的初始值设定项列表中初始化要从函数返回的对象或引用。
return
§8.5:
在参数传递中发生的初始化 [...] 称为复制初始化。
§12.3.1:
显式构造函数构造对象与非显式构造函数一样构造对象,但仅在显式使用直接初始化语法 (8.5) 或强制转换 (5.2.9、5.4) 时才这样做。
转换构造函数是在声明时不带函数说明符的单参数构造函数。编译器使用转换构造函数将对象从第一个参数的类型转换为转换构造函数的类的类型。
评论