编程C++ 开发人员

解释在 C++ 中声明构造函数时 'explicit' 和 'implicit' 关键字之间的区别,以及它们的使用如何影响对象的初始化。

用 Hintsage AI 助手通过面试

答案

在 C++ 中,如果一个构造函数可以使用一个参数进行调用,它默认被认为是 implicit(隐式的)。这种构造函数可以用于 隐式类型转换。为了防止这种情况,可以使用 explicit 关键字。

  • explicit 构造函数禁止隐式转换。

使用 explicit 可以避免意外的转换,例如在将不匹配类型的参数传递给函数或初始化变量时。

示例:

struct Foo { explicit Foo(int x) { /* ... */ } }; Foo a = 10; // 错误,explicit 禁止隐式初始化 Foo b(10); // 可以

如果没有 explicit,Foo a = 10; 的写法将被允许,并可能导致意外的错误。

陷阱问题

问题: 所有使用 explicit 声明的构造函数在使用 = 初始化时都不能被调用吗?
常见回答: 是的,explicit 禁止任何使用 = 的初始化。
正确回答: explicit 只禁止隐式转换。对于直接初始化 (ClassName obj(param);) 的情况下,explicit 构造函数是可以被调用的。而对于复制初始化 (ClassName obj = param;) 的情况下则不能被调用。

示例:

struct A { explicit A(int) {} }; A x = 1; // 错误 A y(1); // 可以

由于对该主题细节的不了解而导致的实际错误示例


故事:在一个项目中,编写了一个没有 explicit 的构造函数,允许通过类型初始化,这导致了函数参数的意外自动转换。这引发了隐藏错误的出现,使调试变得困难。



故事:开发人员没有为容器的构造函数设置 explicit,导致默认构造函数在赋值或传递其他类型时突然被调用。结果是对象创建逻辑不正确,行为不可预测。



故事:一个没有经验的程序员声明了一个 explicit 构造函数,但惊讶于直接初始化使用圆括号可以工作,以为 explicit 也会阻止这种情况。这导致没有使用方便的安全模式,项目中多余的代码。