C++的explicit关键字
exlicit 的用处
关键字告诉编译器,拒绝隐式转换。主要修饰以下情况的构造函数:
构造函数只有一个参数
构造函数有多个参数,但是除了第一个参数外都具有默认值
#include
using namespace std;
class Foo {
public:
Foo(int x){ cout << "Foo(int)"<
输出:
Foo(int)
Foo(int)
Foo(int)
Foo(int)
Foo(double, double)
在 这句发生了隐式类型转换,效果就是调用了并且把42作为参数。隐式类型转换有一些便利之处,也会带来一些隐患。( ref《more effective C++》)
如果使用了 ,将会禁止把42隐式转换为class Foo的实例a,这句将会在编译时报错。
class Foo {
public:
explicit Foo(int x){ cout << "Foo(int)"<
main.cpp:23:13: error: conversion from ‘int’ to non-scalar type ‘Foo’ requested
(更新)C++11 中explicit 关键字还能作用于 C++11 的列表初始化语法
class Foo {
explicit Foo(int x, double y);
...
};
此时下面的代码是不允许的:
Func({42, 3.14}); // Error
Note: 似乎不必要限制这种转换, 接受一个 std::initializer_list 作为参数的构造函数也应当省略 explicit, 以便支持拷贝初始化 (例如 MyType m = {1, 2};) (参考)
More
explicit 可以混用,《C++ F&Q 10.22》有个例子如下, 这里本意是允许double 隐式转换为Foo,但是不允许bool转换为Foo。
#include
class Foo {
public:
Foo(double x) { std::cout << "Foo(double)\n"; }
explicit Foo(bool x) { std::cout << "Foo(bool)\n"; }
};
void yourCode()
{
Foo a = true; //OK: implicitly promotes true to (double)1.0, then calls Foo::Foo(double)
}
但是发现可以通过编译,并且打印如下
Foo(double)
这里的true先被编译器解释为 (double)true, 即1.0 ,然后通过Foo(double) 完成了隐式类型转换。这个与设计的本意不符合,可能会带来困惑或者bug。
何时使用
expilicit 的使用条件如下:
以 《More Effective C++》的例子来看,
class Array{
Array(int size);
bool operator==(const Array& lhs, const Array& rhs);
};
...
Array a(10);
Array b(10);
if(a == b[i]){ // bug!: 本意是 a==b, 但是写错了,但是仍然可以通过编译
//...
}
因此, 如非必要,拒绝隐式类型转换。