C++11 explicit —— 奇牛
C++11 explicit —— 奇牛
1. 隐式转换 (Implicit Conversion)
在 C++ 中,如果一个构造函数可以仅凭一个参数(或在 C++11 后通过初始化列表)调用,编译器默认执行隐式转换。
- 本质:编译器在后台自动调用构造函数,将“原始数据”转换为“类对象”,以匹配函数签名或赋值操作。
2. explicit 的定义
explicit 是一个权限控制符,专门用于修饰构造函数或类型转换操作符。
- 核心功能:禁止编译器在初始化或传参时进行自动类型转换。
- 存在意义:增强代码健壮性,防止因编译器“自作聪明”导致的意外逻辑错误(如:本该传入学生对象的函数,不小心传入了一个整数年龄)。
3. 补充:语法判定规则 (Grammar & Selection Rules)
要掌握 explicit,必须区分以下四种初始化语法。其判定逻辑在于:只要存在 = 号或在非对象位置直接提供原始值,通常就被视为隐式行为。
| 语法范式 | 术语名称 | 显/隐性 | explicit 兼容性 |
|---|---|---|---|
T obj(arg); |
直接初始化 (Direct-init) | 显式 | 允许 |
T obj{arg}; |
直接列表初始化 (Direct-list-init) | 显式 | 允许 |
T obj = arg; |
拷贝初始化 (Copy-init) | 隐式 | 禁止 |
T obj = {arg}; |
拷贝列表初始化 (Copy-list-init) | 隐式 | 禁止 |
void func(T); func(arg); |
传参转换 | 隐式 | 禁止 |
4. 示例代码
#include <iostream>
#include <string>
class Student {
public:
// 显式声明:防止 int 自动转换为 Student
explicit Student(int age)
: _age(age), _name("Unknown") {}
// 显式声明:防止 {int, const char*} 自动转换为 Student
explicit Student(int age, const char* name)
: _age(age), _name(name) {}
void print() const {
std::cout << "Name: " << _name << ", Age: " << _age << std::endl;
}
private:
int _age;
std::string _name;
};
void displayStudent(Student s) {
s.print();
}
int main() {
// 【1. 显式构造:编译通过】
Student s1(18); // 直接初始化
Student s2(17, "Tom"); // 直接初始化(多参数)
Student s5{ 18 }; // 直接列表初始化
Student s6{ 17, "nameless" }; // 直接列表初始化(多参数)
// 【2. 隐式构造:编译报错】
// Student s3 = 18; // Error: 被 explicit 拦截
// Student s4 = {17, "Jerry"}; // Error: 被 explicit 拦截
// displayStudent(20); // Error: 无法将 int 隐式转为参数 s
// 【3. 修正隐式转换的方法】
// 如果必须传参,需通过显式转换手动构造临时对象
displayStudent(Student(20)); // OK
displayStudent(static_cast<Student>(20)); // OK
}
工程惯例:
- 单参数构造函数:几乎必须加
explicit,除非该类本身就是为了包装某种基础类型(如BigInt)。 - 多参数构造函数:建议加
explicit,以防止类似s = {1, "test"}这种缺乏类型信息的写法在代码库中扩散,导致重载解析困难。

浙公网安备 33010602011771号