explicit的作用
如果A类有某个构造函数的单个输入参数,是B类(包括基本数据类型)的对象或引用,则C++的编译器会在需要A类形参的函数调用中,自动调用该构造函数,将B类实参隐式地转换为A类实参。
这种自动类型转换的好处是,避免了定义函数的两个重载版本,代价是隐式调用构造函数会增加调用开销,并可能会带来其他问题。
在标准C++中,新增加了关键字explicit(显式/清楚/明确),(只能)用在带单个参数的构造函数前(或者除了第一个参数外其余参数都有默认值的多参构造函数),告诉编译器,不能使用该构造函数进行隐式类型转换。如果确实想转换,则必须采用显式的类型转换方式来进行。从而避免了可能出现的问题和额外的调用开销。
引用一下Bjarne Stroustrup的例子:
class String{
explicit String(int n);
String(const char *p);
};
String s1 = 'a'; //错误:不能做隐式char->String转换
String s2(10); //可以:调用explicit String(int n);
String s3 = String(10);//可以:调用explicit String(int n);再调用默认的复制构造函数
String s4 = "Brian"; //可以:隐式转换调用String(const char *p);再调用默认的复制构造函数
String s5("Fawlty"); //可以:正常调用String(const char *p);
void f(String);
String g()
{
f(10); //错误:不能做隐式int->String转换
f("Arthur"); //可以:隐式转换,等价于f(String("Arthur"));
return 10; //同上
}
在实际代码中的东西可不像这种故意造出的例子。
发生隐式转换,除非有心利用,隐式转换常常带来程序逻辑的错误,而且这种错误一旦发生是很难察觉的。
原则上应该在所有的构造函数前加explicit关键字,当你有心利用隐式转换的时候再去解除explicit,这样可以大大减少错误的发生。