C++中explicit关键字的含义(c++ explicit关键字可以被子类继承)

C++中explicit关键字的含义(c++ explicit关键字可以被子类继承)

编码文章call10242025-05-09 4:24:513A+A-

技术背景

在C++中,当一个构造函数只有一个必要参数时,它会被视为一个隐式转换函数,能够将参数类型转换为类类型。这种隐式转换在某些情况下是方便的,但也可能会导致意外的行为和难以调试的错误。为了避免这些问题,C++引入了explicit关键字。

实现步骤

1. 未使用explicit关键字的情况

#include <iostream>

struct Foo {
    // 单参数构造函数,可用于隐式转换
    Foo(int x) {}
};

struct Faz {
    // 同样是转换构造函数
    Faz(Foo foo) {}
};

// 参数类型为Foo
void bar(Foo foo) {}

int main() {
    // 转换构造函数允许传递int
    bar(42);
    // 也允许这样的初始化
    Foo foo = 42;
    // 错误!这需要两次转换(int -> Foo -> Faz)
    // Faz faz = 42;
    return 0;
}

在上述代码中,Foo的构造函数允许将int类型隐式转换为Foo类型,因此bar(42)Foo foo = 42;都是合法的。

2. 使用explicit关键字的情况

#include <iostream>

struct Foo {
    // 显式构造函数,防止隐式转换
    explicit Foo(int x) {}
};

struct Faz {
    // 同样是转换构造函数
    Faz(Foo foo) {}
};

// 参数类型为Foo
void bar(Foo foo) {}

int main() {
    // 错误!不允许隐式转换
    // bar(42);
    // 错误!不允许隐式转换
    // Foo foo = 42;
    // 显式调用构造函数
    bar(Foo(42));
    Foo foo(42);
    return 0;
}

在这个例子中,Foo的构造函数被声明为explicit,这意味着编译器不能再使用该构造函数进行隐式转换。因此,bar(42)Foo foo = 42;会导致编译错误,必须显式地调用构造函数。

3. explicit用于转换函数

#include <iostream>

struct X { 
    explicit X(int a); // X可以从int显式构造
    explicit operator bool() const; // X可以显式转换为bool
};

void foo(bool b) { }

int main() {
    X x(0);
    // 错误!X不能隐式转换为bool
    // foo(x);
    // 显式转换
    foo(static_cast<bool>(x));
    return 0;
}

在C++11及以后的版本中,explicit关键字也可以用于转换函数,防止隐式转换。

核心代码

#include <iostream>

// 未使用explicit关键字
class String1 {
public:
    String1(int n); // 分配n字节给String对象
    String1(const char *p); // 用char *p初始化对象
};

String1::String1(int n) {
    std::cout << "String1(int n) called" << std::endl;
}

String1::String1(const char *p) {
    std::cout << "String1(const char *p) called" << std::endl;
}

// 使用explicit关键字
class String2 {
public:
    explicit String2(int n); // 分配n字节
    String2(const char *p); // 用字符串p初始化对象
};

String2::String2(int n) {
    std::cout << "String2(int n) called" << std::endl;
}

String2::String2(const char *p) {
    std::cout << "String2(const char *p) called" << std::endl;
}

int main() {
    // 未使用explicit,允许隐式转换
    String1 s1 = 'x';
    // 使用explicit,不允许隐式转换,编译错误
    // String2 s2 = 'x';
    String2 s2(10);
    return 0;
}

最佳实践

  • 默认使用explicit:对于单参数构造函数,除非有明确的需求,否则应该默认将其声明为explicit,以避免意外的隐式转换。
  • 在接口设计中使用explicit:在类的接口中使用explicit关键字可以强制用户明确表达他们想要的转换,提高代码的可读性和可维护性。

常见问题

1. 为什么explicit关键字只能用于单参数构造函数?

严格来说,explicit关键字可以用于多参数构造函数,但只有当构造函数可以用于隐式转换时才有意义。通常,多参数构造函数不会用于隐式转换,因此explicit关键字在这种情况下的使用较少。

2. explicit关键字对默认构造函数有影响吗?

默认构造函数(无参数构造函数)通常不会用于隐式转换,因此explicit关键字对默认构造函数没有实际影响。

3. explicit关键字可以用于复制构造函数吗?

复制构造函数通常用于对象的复制,而不是隐式转换,因此explicit关键字对复制构造函数没有实际影响。

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4