explicit构造函数的作用与隐式转换陷阱
C++中explicit关键字在构造函数中的作用是什么?为什么单参数构造函数建议标记explicit?explicit在多参数构造函数(C++11起)和转换运算符(C++11)中如何使用?
回答
小字辈
作用:阻止构造函数的隐式类型转换,只允许显式构造。
单参数构造函数——最容易踩坑:
class String {
public:
String(int n); // 可隐式转换: String s = 42;
explicit String(const char*); // 禁止隐式: String s = "hello"; // 错误
};
void foo(String s);
foo(42); // 隐式调用String(42)——有时是bug
foo(String(42)); // 必须显式——意图明确
C++11扩展:explicit可用于多参数构造函数:
struct Point {
explicit Point(int x, int y); // 必须显式构造
};
Point p = {1, 2}; // C++11 列表初始化: 若explicit则可以用
// Point p = 1, 2; // 不行
转换运算符的explicit(C++11):
struct BoolLike {
explicit operator bool() const { return true; }
};
BoolLike bl;
if (bl) { } // OK: 上下文中显式转换允许
bool b = bl; // 错误:需要显式转换
最佳实践:
- 所有单参数构造函数都标记explicit(除非有明确目的支持隐式转换)
- 多参数构造函数通常无需explicit(但列表初始化可能被隐式使用)
operator bool()总是标记explicit——防止意外数值上下文- 隐式转换适合:智能指针(nullptr_t比较)、数值包装类(轻度包装)
- C++20的
explicit(bool)允许条件性explicit(模板中很有用)
C++20变化:explicit(bool)表达式在模板中按条件决定explicit。