C++ explicit显式关键字的实现

 更新时间:2026年02月02日 10:35:12   作者:带土1  
explicit关键字用于禁止类的单参数构造函数进行隐式类型转换,本文主要介绍了C++ explicit显式关键字的实现,具有一定的参考价值,感兴趣的可以了解一下

一、explicit 关键字的核心定义

explicit 是C++中的修饰符关键字唯一的作用场景是修饰类的构造函数,它的核心功能是:禁止编译器对被修饰的构造函数执行「隐式类型转换 / 隐式构造」行为

二、前置知识:什么是「隐式类型转换/隐式构造」?

要理解explicit,必须先理解它要禁止的行为是什么。

触发隐式构造的前提

一个类的构造函数满足以下条件时,编译器就具备了「隐式转换」的能力:
✅ 构造函数是单参数构造函数(只有1个入参);
✅ 或,多参数构造函数,但除第一个参数外,其余参数都有默认值(本质等价于「可单参数调用」的构造函数)。

隐式构造的本质

编译器会自动将「单个入参的值」转换为「当前类的临时对象」,这个转换过程是编译器偷偷完成的,不需要程序员手动写构造代码,所以叫「隐式」。

三、无 explicit 时:隐式构造生效(反面示例)

下面的代码是不加explicit的情况,可以直观看到隐式构造的效果,这也是explicit要解决的场景:

#include <iostream>
using namespace std;

class Test {
public:
    int num;
    // 单参数构造函数:无explicit修饰,支持隐式构造
    Test(int n) : num(n) {
        cout << "构造函数执行: num = " << num << endl;
    }
};

// 测试函数:入参为Test类型对象
void printTest(Test t) {
    cout << "printTest: " << t.num << endl;
}

int main() {
    // 场景1:直接赋值的隐式转换
    Test t1 = 10;  // ✅ 编译通过!编译器自动把 10 → Test(10) 临时对象 → 赋值给t1
    cout << "t1.num = " << t1.num << endl;

    // 场景2:函数传参的隐式转换
    printTest(20); // ✅ 编译通过!编译器自动把 20 → Test(20) 临时对象 → 传给函数
    return 0;
}

运行结果

构造函数执行: num = 10
t1.num = 10
构造函数执行: num = 20
printTest: 20

✅ 结论:无explicit时,编译器帮我们完成了 整型值 → Test对象 的隐式转换,代码能编译运行,但这种「自动转换」往往是风险来源

四、加 explicit 时:隐式构造被禁止(正面示例)

给上述代码的构造函数加上explicit修饰,代码如下,所有隐式转换的写法都会直接编译报错

#include <iostream>
using namespace std;

class Test {
public:
    int num;
    // 单参数构造函数:加explicit修饰,禁止隐式构造
    explicit Test(int n) : num(n) {
        cout << "构造函数执行: num = " << num << endl;
    }
};

void printTest(Test t) {
    cout << "printTest: " << t.num << endl;
}

int main() {
    // 场景1:直接赋值的隐式转换
    Test t1 = 10;  // ❌ 编译报错!explicit禁止了这种隐式转换写法
    // 场景2:函数传参的隐式转换
    printTest(20); // ❌ 编译报错!explicit禁止了这种隐式转换写法

    return 0;
}

报错原因

编译器提示类似:cannot convert 'int' to 'Test' in initialization,核心就是:explicit让编译器失去了「自动转换类型」的权限

五、加 explicit 后,正确的写法:显式构造

⚠️ 重要结论:explicit 只禁止隐式构造,完全不影响「显式构造」
explicit修饰的构造函数,依然可以正常使用,只是必须手动显式调用构造函数,这也是C++推荐的「安全写法」,修改上述main函数的正确代码:

int main() {
    // 正确写法1:标准显式构造(最常用)
    Test t1(10); 
    cout << "t1.num = " << t1.num << endl;

    // 正确写法2:C++11列表初始化(同样属于显式构造)
    Test t2{20};
    cout << "t2.num = " << t2.num << endl;

    // 正确写法3:函数传参时显式构造
    printTest(Test(30));
    printTest(Test{40});

    return 0;
}

运行结果

构造函数执行: num = 10
t1.num = 10
构造函数执行: num = 20
t2.num = 20
构造函数执行: num = 30
printTest: 30
构造函数执行: num = 40
printTest: 40

✅ 结论:显式构造的写法完全不受explicit影响,且逻辑清晰,可读性更高。

六、explicit 的核心注意事项

✅ 注意1:explicit 只对「可单参数调用的构造函数」有效

explicit的修饰对以下构造函数无意义(加了也不会报错,但属于多余写法):

  1. 无参构造函数(Test());
  2. 真正的多参数构造函数(无默认值,比如Test(int a, int b));
    因为这两种构造函数本身就无法触发隐式构造,编译器没有转换的依据。

✅ 注意2:多参数+默认值的构造函数,也需要加 explicit

这是最容易被忽略的坑!比如下面的构造函数,本质是「可单参数调用」,不加explicit依然会触发隐式构造:

class Test {
public:
    int a, b;
    // 多参数,但第二个参数有默认值 → 等价于「可单参数调用」
    Test(int x, int y = 0) : a(x), b(y) {}
};

int main() {
    Test t = 100; // ✅ 编译通过!隐式构造:100 → Test(100, 0)
    return 0;
}

✅ 建议:这种构造函数必须加explicit,写法如下:

explicit Test(int x, int y = 0) : a(x), b(y) {}

✅ 注意3:C++11扩展:explicit 也可以修饰「转换运算符」

C++11标准中,explicit的作用范围被扩大了:除了修饰构造函数,还可以修饰类的转换运算符(operator 类型名),作用依然是:禁止自定义类型到其他类型的隐式转换
示例:

class Test {
public:
    int num = 10;
    // 转换运算符:将Test对象转为int类型
    explicit operator int() const {
        return num;
    }
};

int main() {
    Test t;
    int a = t; // ❌ 编译报错!禁止隐式转换 Test → int
    int b = static_cast<int>(t); // ✅ 正确:显式转换,不受影响
    return 0;
}

✅ 注意4:为什么要禁止隐式构造?—— 核心价值

explicit不是语法糖,而是C++的安全机制,它的设计初衷是:避免「意外的隐式转换」导致的逻辑错误和难以排查的bug

  • 隐式转换是编译器的「自动行为」,程序员很容易忽略这个转换过程,导致代码逻辑和预期不符;
  • 隐式转换会生成临时对象,可能带来不必要的性能开销(虽然现代编译器会优化,但依然不推荐);
  • 显式构造的代码可读性更高,谁看都知道这里是「创建了一个对象」,没有歧义。

七、最佳实践(行业通用规范)

所有满足「可单参数调用」的构造函数,都建议加上 explicit 修饰!

除非你有明确的业务需求需要用到隐式构造(这种场景极少,比如std::string的构造函数允许const char*隐式转为string,是为了兼容C语言的字符串写法),否则一律加上explicit,这是C++开发的「行业最佳实践」,也是大厂面试的高频考点。

✨ 核心知识点总结(精华浓缩)

  1. explicit 是修饰符,仅用于修饰类的构造函数(C++11可修饰转换运算符);
  2. 核心作用:禁止编译器的隐式类型转换/隐式构造
  3. 生效前提:构造函数是「单参数」或「多参数+其余参数有默认值」;
  4. explicit后,只能用显式构造Test t(n) / Test t{n}),隐式写法(Test t = n)编译报错;
  5. explicit不影响显式构造,是C++的安全机制,推荐无脑加;
  6. 本质区别:隐式是「编译器自动转」,显式是「程序员手动写」,显式代码更安全、可读性更高。

到此这篇关于C++ explicit显式关键字的实现的文章就介绍到这了,更多相关C++ explicit显式关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++实现ping程序实例

    C++实现ping程序实例

    这篇文章主要介绍了C++实现ping程序实例,涉及C++对于ICMP数据包的发送与回显处理,具有一定的实用价值,需要的朋友可以参考下
    2014-10-10
  • C++实践分数类中运算符重载的方法参考

    C++实践分数类中运算符重载的方法参考

    今天小编就为大家分享一篇关于C++实践分数类中运算符重载的方法参考,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C++解决TCP粘包的问题实现

    C++解决TCP粘包的问题实现

    本文主要介绍了C++解决TCP粘包的问题实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • 你只用do-while来实现循环?太浪费了

    你只用do-while来实现循环?太浪费了

    这篇文章主要介绍了你只用do-while来实现循环?太浪费了,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 利用Matlab绘制一款专属进度条

    利用Matlab绘制一款专属进度条

    MATLAB自带的进度条是很简单的,这样的进度条显得冷冰冰的。因此,本文将用Matlab来DIY一款专属的进度条,感兴趣的小伙伴可以了解一下
    2022-02-02
  • C/C++中数据类型转换详解及其作用介绍

    C/C++中数据类型转换详解及其作用介绍

    这篇文章主要介绍了C/C++中数据类型转换详解及其作用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • OpenCV透视变换应用之书本视图矫正+广告屏幕切换

    OpenCV透视变换应用之书本视图矫正+广告屏幕切换

    透视变换是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面绕迹线旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。本文将为大家介绍两个OpenCV透视变换应用,需要的可以参考一下
    2022-08-08
  • C语言小程序 杨辉三角示例代码

    C语言小程序 杨辉三角示例代码

    输入要显示的杨辉三角的行数,会打印出金字塔型的杨辉三角,不过行数太多的话,效果不太好,可以再调整一下格式控制
    2013-07-07
  • C++类中隐藏的几个默认函数你知道吗

    C++类中隐藏的几个默认函数你知道吗

    这篇文章主要为大家详细介绍了C++类中隐藏的几个默认函数,使用数据库,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C++ 字符串去重排序实例代码

    C++ 字符串去重排序实例代码

    这篇文章主要介绍了C++ 字符串去重排序实例代码的相关资料,需要的朋友可以参考下
    2017-05-05

最新评论