explicit关键字的用法和语法用途
背景:QT Creator 默认生成的代码 explicit Dialog(QWidget *parent = 0)
中,有这么一个关键字explicit,用来修饰构造函数。以前C++写程序的时候,基本上没有碰到这个关键字,那么这个关键字是做什么用的呢?
权威:
explicit修饰构造函数是用来防止隐式转换的,具体一点就是explicit 是避免构造函数的参数自动转换为类对象的标识符。
网上有人这么解释:
“避免一些无意的潜在错误,很多时候一个不经意的赋值本来是错的,结果没有explicit,赋值对象又可隐式转换为参数这种类型,也就成了一个难以发现的BUG ”
再通俗一点:
“google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换,缺点无。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。
effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期 (往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit。我鼓励你遵循相同的政策。”
用一段简单代码来验证一下
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a){
data = a;
}
void show(){
cout << "data = " << data << endl;
}
private:
int data;
};
int main()
{
Test t = 2; // 将一个常量赋给了一个对象
t.show();
return 0;
}
程序输出:
Starting /home/~/build-2-1-3-Desktop_Qt_5_8_0_GCC_64bit-Debug/2-1-3...
data = 2
/home/~/build-2-1-3-Desktop_Qt_5_8_0_GCC_64bit-Debug/2-1-3 exited with code 0
为什么会这样呢?原来C++通过隐式转换,构造了一个临时对象Test(2),将它赋给了t(这里调用了默认的构造函数,而不是重载的“=”,因为这是在对象创建的时候)。那么,如果给构造函数加上关键字 explicit ,构造函数变成了explicit Test(int a)
,再次编译,编译器就会报错。这时,就只能显式地使用构造函数了Test t = Test(2) 。
报错信息:
/home/~/2-1-3/main.cpp:20: error: conversion from ‘int’ to non-scalar type ‘Test’ requested
Test t = 2; // 将一个常量赋给了一个对象
^