c++学习笔记分享--explicit关键字
2026/6/24 8:07:40 网站建设 项目流程

日常分享整合的学习笔记:

首先,explict中文意思是 清楚明白的;易于理解的;明确的;直言的 ;显式;

在编程中:

explicit用来告诉编译器:“不要偷偷用这个构造函数做隐式类型转换!

1.先看一个反面例子(没有 explicit)

假设有一个类:

class Number { public: Number(int x) { // 只有一个参数的构造函数 value = x; } private: int value; }; void printNumber(Number n) { // 假装打印一下... } int main() { printNumber(42); // 这里发生了甚么? }

printNumber(42);

在这里你本来想传入一个Number类给printNumber,但你传错了

而且这里发生了隐式类型转换,等价于:

Number n = 42; //这个是可以编译过的,可以试一下并输出一下value成员变量,结果是42 //相当于调用构造函数 Number n(42);

这很奇怪对吧?

因为编译器看到printNumber需要Number对象,但你传了一个int,恰好是Number类对应的构造函数参数,于是它会自动调用Number(int)构造函数把42变成Number(42)。这就是隐式类型转换

加上 explicit 之后:

class Number { public: explicit Number(int x) { // 加了个 explicit value = x; } private: int value; }; void printNumber(Number n) { /* ... */ } int main() { // printNumber(42); // 这行现在会报错! printNumber(Number(42)); // 必须显式构造,这样写才行 }

加了explicit后,编译器不会再偷偷帮你把42转换成Number,你必须自己明确写出构造过程。这让代码意图更清晰,也避免了一些隐蔽的错误。

2. 多参数构造函数(C++11 起)

从 C++11 开始,explicit也可以用在多参数构造函数上。它的作用是禁止使用花括号初始化列表进行隐式转换

class Point { public: explicit Point(int x, int y) : mx(x), my(y) {} //初始化列表 private: int mx, my; }; void draw(Point p) {} int main() { draw({1, 2}); // ❌ 错误:不能隐式转换 draw(Point{1, 2}); // ✅ 正确:显式构造 }

注意:这里说的是花括号初始化列表{1, 2}这种写法。如果是draw(Point(1, 2))圆括号构造,本来就没有隐式转换的问题。

3.常见疑惑与陷阱

疑惑 1:explicit 会影响拷贝/移动构造函数吗?

不影响。explicit只影响普通构造函数转换运算符。拷贝构造函数和移动构造函数即使加了explicit,也不影响它们正常的拷贝/移动行为(但一般没人给它们加)。

class Foo { public: explicit Foo(int) {} // 普通构造,禁止隐式转换 // 拷贝构造函数不需要 explicit Foo(const Foo&) = default; };

疑惑 2:explicit 和 = default / = delete 一起用?

可以。比如你想禁止某些隐式转换,但仍然保留默认构造:

class Bar { public: explicit Bar(int) = default; // 显式构造且使用默认实现 Bar(double) = delete; // 完全禁止 double 类型的构造 };

疑惑 3:explicit 到底能不能提高性能?

通常不能。explicit不影响运行时的性能,它只影响编译器的行为——是否允许某种写法通过编译。所以不用担心加了explicit会让程序变慢

疑惑 4:什么时候应该不加 explicit?

很少见,但有几种情况可以考虑不加:

  1. 包装类:比如一个类只是对底层类型的一层薄包装,而且经常需要和底层类型互操作。例如std::string_view可以用const char*隐式构造。

  2. 数值类型:比如你自己写的BigInteger类,允许int隐式转换成它,可能会方便一些。

  3. 仿函数/适配器:某些设计模式里,隐式转换反而让代码更简洁。

不过作为新手,先一律加explicit,等你真的遇到需要去掉的情况再改,这样最安全。

4.什么时候用?

建议:所有单参数构造函数都建议加上explicit,除非你有非常明确的理由需要隐式转换(这种情况极少)。

比如标准库里的std::vector有一个explicit vector(size_t count),就是为了防止你不小心写出这样的代码:

std::vector<int> v = 10; // 如果没有 explicit,这行可能就编译过了,但语义很奇怪

End.............

如果这篇笔记对你有帮助,留下赞蟹蟹

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询