explicit关键字用于修饰类的单参数或带默认值的多参数构造函数,禁止隐式类型转换和拷贝初始化,仅允许显式调用(如a(42)或a{42}),必须声明在类内构造函数首部,不可用于实现文件或无关函数。

explicit关键字必须写在构造函数声明处
它只能出现在类定义内部的构造函数声明前,不能写在实现(.cpp 文件里的函数体)中,也不能加在普通函数、析构函数或转换运算符(operator T())的声明上——除非是 C++11 起的 explicit operator T(),但那是另一回事。
常见错误是试图在定义处加 explicit,比如:
class A {
public:
A(int x);
};
A::A(int x) { /* ... */ } // ❌ 这里加 explicit 无效,编译报错
正确写法只在声明位置:
class A {
public:
explicit A(int x); // ✅ 唯一合法位置
};
哪些构造函数适合加explicit
加 explicit 不是看参数个数,而是看它是否“可被当作类型转换用”。编译器会把以下两类构造函数视为潜在的隐式转换入口:
- 单参数构造函数,如
A(int)、A(const std::string&) - 多参数构造函数,但除第一个外其余都有默认值,如
A(int, bool = true)—— 它等价于单参数调用
这两类一旦没加 explicit,就可能触发 A a = 42; 或 func(10)(其中 func 接收 A)这类隐式转换。
反例:无参构造函数(A())、多参且无默认值的构造函数(A(int, double))加 explicit 没意义,语法允许但不生效。
explicit对初始化方式的影响
加了 explicit 后,并非“不能用”,而是限制了调用形式。这些写法仍然合法:
-
A a(42);—— 直接初始化,始终允许 -
A a{42};—— 列表初始化,C++11 起明确允许explicit构造函数 -
func(A(42));或func(static_cast<a>(42));</a>—— 显式构造或转型
但这些会被拒绝:
-
A a = 42;—— 拷贝初始化,触发隐式转换,编译失败 -
func(42);—— 如果func参数是const A&或A,且没匹配其他重载,编译失败
容易忽略的兼容性细节
explicit 是 C++98 就有的关键字,但它的语义在 C++11 后才扩展到转换运算符;而列表初始化(A{42})对 explicit 构造函数的支持,是从 C++11 开始保证的。如果你的项目需兼容老编译器(如 VS2010 或 GCC 4.4 以前),要注意 A{42} 可能不被接受。
另一个易漏点:模板类中的构造函数,explicit 必须随模板参数一起声明,不能延迟到特化时补加——否则特化版本仍可能隐式转换。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











