在 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 也会阻止这种情况。这导致没有使用方便的安全模式,项目中多余的代码。