惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
博客园_首页
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
小众软件
小众软件
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
罗磊的独立博客
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家
量子位
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog

博客园 - zhaotianff

WPF控件样式和模板全解析-RadioButton控件 WPF控件样式和模板全解析-ToggleButton控件 WPF控件样式和模板全解析-CheckBox控件 软件架构风格与软件架构设计方法 WPF控件样式和模板全解析-Label控件 WPF控件样式和模板全解析-Button控件 Windows一直卡在检查更新的解决方案 - zhaotianff - 博客园 AI时代,程序员应该何去何从? 如何解决Windows 10/11 删除打印机时,拒绝访问的问题 解决IIS服务器typecho上传附件后无法访问的问题 Visual Studio编译过程中拷贝文件的一些实用小技巧 Jenkins快速入门教程 .NET是什么?为什么要选择.NET? 如何在WPF中实现类似DevOps的自动化流程 一文带你搞懂医疗器械设计开发全生命周期 Windows如何清除本机记录的git用户名和密码 HL7协议详解 医疗行业 GDT 数据格式详解 一文带你搞懂C# 异步编程(async/await)底层原理 如何在C#中使用Chromium headless(无头模式)浏览器 不同.NET版本中的WPF新增功能 如何在WPF中使用 Fluent 主题 Windows平台下的各种原生UI框架介绍 C#如何Hook托管函数 WinDbg 用户层调试进阶教程 Windows编程的一些基础理论 推荐一款优秀的Windows经典文件管理器项目-WinFile Windows如何阻止应用程序联网 如何在WPF中捕获窗口外的事件 如何查看Windows进程的启动来源
C++中的explicit关键字
zhaotianff · 2026-08-05 · via 博客园 - zhaotianff

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