C++ explicit关键字浅析

explicit关键字

今天在看std::thread的时候,发现他的构造函数是这样的:

explicit thread(Fn&& fn, Args&&... args);

explicit这个关键字很眼熟,因为在Qt中默认的构造函数也是用的这个关键字:

explicit Camera(QObject *parent = nullptr);

秉着消灭知识盲点的态度,在这记录一下explicit关键字的用法。


作用:
指定构造函数或转换函数 (C++11起)为显式 (explicit), 即它不能用于隐式转换和复制初始化。
explicit 的反义词是 implicit ,类默认的构造函数就是隐式构造函数 (implicit)。
explicit 只能修饰含有一个参数的构造函数,或除第一个参数外其余参数都有默认值的构造函数。

代码及分析:

class Size
{
public:
    Size(int size)
    {
        cout << size;
    }

    Size(char *str)
    {
        int size = sizeof(str);
        cout << size;
    }
};

Size s1(1);
Size s2 = 1;
Size s3("explicit");
Size s4 = "implicit";

以上代码在实例化时,编译都是OK的。
对于s1、s3,调用的都是显示构造函数,而s2、s4调用的是隐式构造函数。
对于隐式转换,可以这么理解:

Size s2 = 1;
	|
	| 等价于
	↓
int ntemp = 1;
Size s2(ntemp);

Size s4 = "implicit";
	|
	| 等价于
	↓
char *ptemp = "implicit";
Size s4(ptemp);

当在构造函数前添加 explicit 关键字后,s2、s4的实例化会提示报错:不存在从 xxx 转换到 xxx 的适当构造函数。

上述是单个参数构造函数,下面再举另外一个例子,除第一个参数外其余参数都有默认值:

class Point
{
public:
    int x;
    int y;
    explicit Point(int x, int y = 0) : x(x), y(y){};
};

Point p1(1);
Point p2 = 1; // 会报错

Effective C++ 中有提到:
被声明为explicit的构造函数通常比其 non-explicit 兄弟更受欢迎, 因为它们禁止编译器执行非预期 (往往也不被期望) 的类型转换. 除非我有一个好理由允许构造函数被用于隐式类型转换, 否则我会把它声明为explicit. 我鼓励你遵循相同的政策.

Google Style Guide 中也有提到:
不要在构造函数中调用虚函数, 也不要在无法报出错误时进行可能失败的初始化.

总结:
对于单参构造函数、首项参数无默认值的构造函数,为了不让c++太放飞自我,十分建议使用 explicit 关键字,取消编译器执行一些非预期的类型转换!

你可能感兴趣的:(C++,c++,qt,开发语言)