1. 构造函数与关键字explicit
1.1 关键字explicit
- 针对C++中一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色,一是个构造器 ;二是个默认且隐含的类型转换操作符。
- 所以,有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型正好是AAA单参数构造器的参数类型, 这时候编译器就自动调用这个构造器, 创建一个AAA的对象。这样看起来好象很酷, 很方便。 但在某些情况下, 却违背了本意。
- 这时候就要在这个构造器前面加上关键字explicit修饰,指定这个构造器只能被明确的调用,不能作为类型转换操作符被隐含的使用。可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。。
注:explicit构造函数是用来防止隐式转换的,因为声明为explicit的构造函数不能在隐式转换中使用。
1.2 关键字explicit的应用
- 不可否认,在实际项目开发中确实很少有人会使用explicit关键字,在但在MFC库或标准库中相关类中explicit出现的频率是很高的。
了解explicit关键字的功能及其使用,对于我们阅读使用库是很有帮助的,而且在编写自己的代码时也可以尝试使用。既然C++语言提供这种特性,我想在有些时候这种特性将会非常有用。
#include <iostream> using namespace std; class Test1 { public: Test1() { num1=0; num2=0; }//默认构造函数 Test1(int n1) { num1=n1; }//普通构造函数 Test1(int n1, int n2) { num1=n1; num2=n2; }//普通构造函数 void set_num1(int n1) { num1 = n1; } int get_num1() { return num1; } void set_num2(int n2) { num2 = n2; } int get_num2() { return num2; } private: int num1; int num2; }; class Test2 { public: Test2() { num1=0; num2=0; }//默认构造函数 Test2(int n1, int n2) { num1=n1; num2=n2; }//普通构造函数 void set_num1(int n1) { num1 = n1; } int get_num1() { return num1; } void set_num2(int n2) { num2 = n2; } int get_num2() { return num2; } private: int num1; int num2; }; class Test3 { public: Test3() { num1=0; num2=0; }//默认构造函数 explicit Test3(int n1) { num1=n1; }//explicit(显式)构造函数 Test3(int n1, int n2) { num1=n1; num2=n2; }//普通构造函数 void set_num1(int n1) { num1 = n1; } int get_num1() { return num1; } void set_num2(int n2) { num2 = n2; } int get_num2() { return num2; } private: int num1; int num2; }; int main() { //Test1 Test1 t1; cout<<"Test1 t1;//执行成功"<<endl<<"num1="<<t1.get_num1()<<" num2="<<t1.get_num2()<<endl; t1 = 11; cout<<"Test1 t1 = 11;//执行成功"<<endl<<"num1="<<t1.get_num1()<<" num2="<<t1.get_num2()<<endl; t1 = Test1(12); cout<<"t1 = Test1(12);//执行成功"<<endl<<"num1="<<t1.get_num1()<<" num2="<<t1.get_num2()<<endl; t1 = Test1(12, 21); cout<<"t1 = Test1(12, 21);//执行成功"<<endl<<"num1="<<t1.get_num1()<<" num2="<<t1.get_num2()<<endl; cout<<endl; //Test2 Test2 t2; cout<<"Test2 t2;//执行成功"<<endl<<"num1="<<t2.get_num1()<<" num2="<<t2.get_num2()<<endl; //t2 = 11; //error C2679: 二进制“=”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换) cout<<"Test2 t2 = 11;//编译不成功"<<endl; //t2 = Test2(12); //error C2440: “<function-style-cast>”: 无法从“int”转换为“Test2” cout<<"t1 = Test1(12);//编译不成功"<<endl<<"num1="<<t2.get_num1()<<" num2="<<t2.get_num2()<<endl; t2 = Test2(12, 21); cout<<"t2 = Test2(12, 21);//执行成功"<<endl<<"num1="<<t2.get_num1()<<" num2="<<t2.get_num2()<<endl; cout<<endl; //Test3 Test3 t3; cout<<"Test3 t3;//执行成功"<<endl<<"num1="<<t3.get_num1()<<" num2="<<t3.get_num2()<<endl; //t3 = 11; //error C2679: 二进制“=”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换) cout<<"Test3 t3 = 11;//编译不成功"<<endl; t3 = Test3(12); cout<<"t3 = Test3(12);//执行成功"<<endl<<"num1="<<t3.get_num1()<<" num2="<<t3.get_num2()<<endl; t3 = Test3(12, 21); cout<<"t3 = Test3(12, 21);//执行成功"<<endl<<"num1="<<t3.get_num1()<<" num2="<<t3.get_num2()<<endl; cout<<endl; system("pause"); return 0; } =>Test1 t1 = 11;//执行成功 num1=11 num2=-858993460 t1 = Test1(12);//执行成功 num1=12 num2=-858993460 t1 = Test1(12, 21);//执行成功 num1=12 num2=21 Test2 t2;//执行成功 num1=0 num2=0 Test2 t2 = 11;//编译不成功 t1 = Test1(12);//编译不成功 num1=0 num2=0 t2 = Test2(12, 21);//执行成功 num1=12 num2=21 Test3 t3;//执行成功 num1=0 num2=0 Test3 t3 = 11;//编译不成功 t3 = Test3(12);//执行成功 num1=12 num2=-858993460 t3 = Test3(12, 21);//执行成功 num1=12 num2=21
注:隐式转换常常带来程序逻辑的错误,而且这种错误一旦发生是很难察觉的。尽量不要使用隐式转换。
参考文献:
[1]《C++全方位学习》范磊——第十章
[2] 百度搜索关键字:C++函数、构造函数、关键字explicit