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 };

 

image

 

结论:

1、在C++中如果定义了这种可空类型的构造函数,就不能再定义默认构造函数了。

2、如果定义了可空类型的构造函数,不管传参或不传参都会调用这个构造函数

 

现在我们来看第2个问题,就是为什么要加explicit关键字

在C++中这个关键字是必须要加的,因为它会引发隐式转换的一些问题。

例如这里的构造函数定义是

1 MainWindow(QWidget *parent = nullptr);

如果我不加explicit关键字,

那么下面的调用都是被允许的

1 MainWindow w1("abc");
2 MainWindow w2(123);

没有explicit关键字,编译器可能会自动将整数/字符串转换为类QWidget指针。

这种隐式转换有时可能不是我们所期望的,所以就需要explicit关键字来进行约束。

加上explicit关键字后,上面的调用就会报错。

image

 

在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++必须通过关键字来限制类型转换,否则可能会出现一些意料之外的事。

 

posted @ 2026-08-05 18:01  zhaotianff  阅读(5)  评论(0)    收藏  举报