explicit 关键字用于禁止编译器对单参数构造函数(含默认参数可单参调用)进行隐式类型转换,只允许显式调用;如 String s = "hello"; 或传参时自动转临时对象均被禁止,避免歧义。
explicit 关键字用于修饰构造函数(C++11 起也支持转换运算符),它的核心作用是禁止编译器进行隐式类型转换,只允许显式调用构造函数完成对象初始化。
当类有一个单参数构造函数(或有默认参数导致实际可单参数调用)时,编译器可能悄悄把它当作“类型转换函数”来用——这往往不是你想要的,容易引发歧义或意外行为。
String s = "hello"; 看似赋值,实则调用了 String(const char*) 构造函数String,你传入 "world",编译器自动转成临时 对象
在构造函数声明前加 explicit:
class String {
public:
explicit String(const char* s); // ✅ 禁止隐式转换
// String s = "abc"; // ❌ 编译错误
// func(someString); // 若 func 接收 String,传 "abc" 会报错
// String s("abc"); // ✅ 显式调用,合法
// String s = String("abc"); // ✅ 显式构造再拷贝,合法(但通常直接用前者)
};防止类到其他类型的隐式转换:
class Number {
int val_;
public:
explicit operator int() const { return val_; } // ✅ 禁止自动转 int
// int x = n; // ❌ 错误:不能隐式转换
// int x = static_cast(n); // ✅ 必须显式转换
// printf("%d", n); // ❌ 即使 printf 需要 int,也不自动转
}; 不是所有单参构造函数都要加 explicit。常见例外:
std::unique_ptr(raw_ptr) ):设计上就鼓励从裸指针安全构建,隐式转换在此语境下是预期行为std::complex(3.0) ):数学语义清晰,隐式构造更自然func(MyClass(42)) 或 MyClass x = 42
; 的简洁语法,且已评估过歧义风险不复杂但容易忽略:只要构造函数形参能由一个参数推导出来(含默认参数),又没加 explicit,它就可能成为隐式转换的入口。加 explicit 是防御性编程的低成本高回报实践。