# C++ 中 explicit 的作用

面试高频指数:★★★☆☆

在 C++ 中,explicit 通常用于构造函数的声明中,用于防止隐式转换。 当将一个参数传递给构造函数时,如果构造函数声明中使用了 explicit 关键字,则只能使用显式转换进行转换,而不能进行隐式转换。

这种机制可以防止编译器自动执行预期外的类型转换,提高代码的安全性。

# 什么是隐式类型转化

就是当你只有一个类型T1,但是当前表达式需要类型为T2的值,如果这时候T1自动转换为了T2,那么这就是隐式类型转换。

举个例子:

int a = 0;
long b = a + 1; // int 转换为 long
 
if (a == b) {
    // 默认的operator==需要a的类型和b相同,因此也发生转换
}

# explicit 的作用

接下来通过一个例子来详细解释 explicit 的作用。

有一个类 MyInt,表示一个整数,并且有一个构造函数可以将 int 类型的参数转换为 MyInt 类型:

class MyInt {
public:
    MyInt(int n) : num(n) {}
private:
    int num;
};

我们可以使用下面的代码来创建一个 MyInt 对象:

MyInt a = 10; // 注意,这段代码有两个步骤: 1. int 类型的 10 先隐式类型转换为 MyInt 的一个临时对象
              //   2. 隐式类型转换后的临时对象再通过复制构造函数生成 a

(PS:可能有些同学会说编译器会用复制省略(copy elision)优化这段代码,最终不会有中间这个临时对象产生,但是这是编译器的优化行为,我们暂时不考虑

在一些情况下,上面这种隐式转换可能会导致问题。 例如,考虑下面的函数:

void f(MyInt n) {
    // do something
}

如果我们调用这个函数,并传递一个 int 类型的值作为参数,如下所示:

f(10);

这也会编译通过,因为编译器会将 int 类型的值隐式转换为 MyInt 类型的对象。

但或许,有些情况下,我们并不期望 f 函数可以接受一个 int 类型的参数,这是预期外的,可能会导致错误的结果。

那么如果希望只接受 MyInt 类型的参数,就可以将构造函数声明加上 explicit

class MyInt {
public:
    explicit MyInt(int n) : num(n) {}
private:
    int num;
};

这样,上面的调用语句将会导致编译错误,因为不能使用隐式转换将 int 类型的值转换为 MyInt 类型。

必须使用显式转换,如下所示:

f(MyInt(10));

所以大家日常可以使用 explicit 关键字可以防止不必要的隐式转换,提高代码的可读性和安全性。

尤其是构造函数参数只有一种类型的,强烈建议加上 explicit,目前我们部门的代码合并流水线就会按这个规则扫描。

以下是 Google C++ 代码规范中的说明:

Google C++ 风格指南 (opens new window)

最新原创的文章都先发布在公众号,欢迎关注哦~,
扫描下方二维码回复「CS」可以获得我汇总整理的计算机学习资料~

编程指北图片
@2021-2024 编程指北 版权所有 粤ICP备2021169086号-2