explicit 主要防止单参数构造函数引发的隐式类型转换,包括拷贝初始化(如 String s = "hello")、函数传参(如 func("world"))等场景;它不阻止显式调用或直接初始化。
explicit 用来禁止编译器执行单参数构造函数的隐式类型转换。
当类有一个只接受一个参数的构造函数(或有默认值、能用一个参数调用的构造函数)时,编译器可能自动用该参数“悄悄”构造对象。explicit 就是告诉编译器:不许这样干。
String s = "hello"; —— 如果 String 有 String(const char*) 构造函数且没加 explicit,这行会隐式调用构造函数;加了 explicit 后,这行直接报错。String,你传入 "world",没 explicit 就会自动转成 String 对象;加了 explicit 就必须显式写成 func(String("world"))。= 形式)受影响,直接初始化(String s("hello"))不受影响。只要这个单参数构造函数的语义不是“类型等价转换”,就建议加上。典型场景:
FileHandle(int fd))—— 你不会希望整数被悄悄变成文件句柄。Money(double amount))—— Money m = 99.9; 看似方便,但容易掩盖精度丢失或单位混淆问题。explicit 只对单参数构造函数(含可变参但实际只用一个参数的情况)有效;多参数构造函数本来就不会隐式调用,所以 explicit 对它们无意义(C++11 起允许给多参构造函数加 explicit,用于禁止大括号隐式转换,但那是另一回事)
。
它不阻止显式调用,也不影响赋值运算符重载。
基本上就这些。加 explicit 不是限制能力,而是让接口更清晰、错误更早暴露。