C++程序员对于explicit这个关键字其实不是很熟悉,至少我是如此;原因在于其使用范围不大,而且作用也没有那么大。
但是这不是说明我们的程序中不需要这个关键字,按Google的C++编程规范和Effective C++的推荐看,我们最好将只有一个参数的构造函数都加上这个关键字,这同时也是cppcheck的要求。
explicit意味着明确的,确定的,这表明这个构造函数是无法隐式转换的,其反义词正式implicit。没有了隐式转换,我们则需要显式使用某个类型的构造函数,如此,可以规避很多不那么能拿得出手的外部类的调用。
指定构造函数或转换函数(从c++ 11开始)是显式的,也就是说,它不能用于隐式转换和复制初始化
一个构造函数只有一个非默认参数(从c++ 11开始),没有explicit声明的,称为转换构造函数。
我们来看一个使用explicit 的代码
class explicitConstruct
{
public:
explicitConstruct();
explicitConstruct(int i){
std::cout << "we use interger parameter is "<<i <<"
";
}
explicitConstruct(int i,int j) {
std::cout << "we use double interger parameter is "<<i<<" and "<<j<<"
";
}
};
class explicitConstructB
{
public:
explicit explicitConstructB(int i){
std::cout << "we use explicit explicitConstructB interger parameter is "<<i <<"
";
}
explicit explicitConstructB(int i,int j){
std::cout << "we use explicit explicitConstructB double interger parameter is "<<i<<" and "<<j<<"
";
}
};
};
explicitConstruct和explicitConstructB类的唯一区别是explicitConstructB的构造函数加入了explicit。
以下是测试代码
explicitConstruct i(3);//ok
explicitConstruct j(3,4); //ok
explicitConstructB ii(3);//ok
explicitConstructB jj(3,4);//ok
explicitConstruct k = 3;//ok
explicitConstruct l = {3,4};//ok
// explicitConstructB kk = 3; //error! copy-initialization does not consider explicitConstructB::explicitConstructB(int)
// explicitConstructB ll = {3,4};///error! copy-initialization does not consider explicitConstructB::explicitConstructB(int,int)
explicitConstructB kkk = explicitConstructB(3);//ok
explicitConstructB lll = explicitConstructB(3,4);//ok
测试代码很清楚的说明了explicit关键字发挥的作用,即让类对象的构造过程无法使用隐式转换的方式调用拷贝初始化。这样做的好处在于,我们可以严格控制构造器参数的类型,避免发生歧义。