C++中explicit关键字的含义(c++ explicit关键字可以被子类继承)
技术背景
在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关键字对复制构造函数没有实际影响。