C++中的explicit关键字
在Qt默认生成的mainwindow.h中,可以看到如下的代码
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 6 QT_BEGIN_NAMESPACE 7 namespace Ui { 8 class MainWindow; 9 } 10 QT_END_NAMESPACE 11 12 class MainWindow : public QMainWindow 13 { 14 Q_OBJECT 15 16 public: 17 explicit MainWindow(QWidget *parent = nullptr); 18 ~MainWindow() override; 19 20 private: 21 Ui::MainWindow *ui; 22 }; 23 #endif // MAINWINDOW_H
我第一次看到这一行时,存在两个疑问
1 explicit MainWindow(QWidget *parent = nullptr);
1、MainWindow类,我如果不传参数,到底是调用空的构造函数,还是调用这个可空的构造函数
2、explicit关键字的作用是什么。
关于第1个问题,我尝试了一下在C#中的情况。
我定义了一下MyClass类,只增加了传递string类型的一个构造函数
1 public class MyClass 2 { 3 public MyClass(string name = "") 4 { 5 6 } 7 }
当我调用时,下面两种都是调用的传递可空string类型的这个构造函数
1 MyClass myClass = new MyClass(); 2 MyClass myClass1 = new MyClass("abc");
如果我再增加一个默认的构造函数
1 public MyClass() 2 { 3 4 }
那么下面这种方式就会调用默认的构造函数
1 MyClass myClass = new MyClass();
但是这种写法在C++中是不行的,会报错
1 class MainWindow : public QMainWindow 2 { 3 Q_OBJECT 4 5 public: 6 explicit MainWindow(QWidget *parent = nullptr); 7 MainWindow(); 8 ~MainWindow() override; 9 10 private: 11 Ui::MainWindow *ui; 12 };

结论:
1、在C++中如果定义了这种可空类型的构造函数,就不能再定义默认构造函数了。
2、如果定义了可空类型的构造函数,不管传参或不传参都会调用这个构造函数
现在我们来看第2个问题,就是为什么要加explicit关键字
在C++中这个关键字是必须要加的,因为它会引发隐式转换的一些问题。
例如这里的构造函数定义是
1 MainWindow(QWidget *parent = nullptr);
如果我不加explicit关键字,
那么下面的调用都是被允许的
1 MainWindow w1("abc"); 2 MainWindow w2(123);
没有explicit关键字,编译器可能会自动将整数/字符串转换为类QWidget指针。
这种隐式转换有时可能不是我们所期望的,所以就需要explicit关键字来进行约束。
加上explicit关键字后,上面的调用就会报错。

在C#中不会出现这种隐式转换的问题,传递不正确的类型会直接报错。
除非是自己定义类时,定义了强制类型转换逻辑,否则不会自己进行转换。
假设我定义了一个Hunam类型和Student类型,并为Student类型增加了一个可空的构造函数
1 public class Human 2 { 3 4 } 5 6 public class Student 7 { 8 public Student(Human human = null) 9 { 10 11 } 12 }
然后我们创建几个实例
1 //正确 2 Student student = new Student(); 3 Student student1 = new Student(human1); 4 5 //错误 6 Student student2 = new Student("张三");
此时我们在Student类中增加强制类型转换
隐式转换
1 public class Human 2 { 3 /// <summary> 4 /// 从string到Human的强制类型转换(隐式转换) 5 /// </summary> 6 /// <param name="name"></param> 7 public static implicit operator Human(string name) 8 { 9 return new Human(); 10 } 11 }
这样下面的调用就是合法的
1 Student student2 = new Student("张三");
显式转换
1 public class Human 2 { 3 /// <summary> 4 /// 从string到Human的强制类型转换(显式转换) 5 /// </summary> 6 /// <param name="name"></param> 7 public static explicit operator Human(string name) 8 { 9 return new Human(); 10 } 11 }
这样下面的调用就是合法的
1 Student student2 = new Student((Human)"张三");
总结:
1、C#不需要通过关键字来限制类型转换,如果需要自动进行类型转换,还需要增加自定义类型转换逻辑。
2、C++必须通过关键字来限制类型转换,否则可能会出现一些意料之外的事。

浙公网安备 33010602011771号