允许编译器进行一次隐式转换以将参数解析为函数。这意味着编译器可以使用可用单个参数调用的构造函数从一种类型转换为另一种类型,以便为参数获取正确的类型。
这是一个带有构造函数的示例类,可用于隐式转换:
class Foo
{
public:
// single parameter constructor, can be used as an implicit conversion
Foo (int foo) : m_foo (foo)
{
}
int GetFoo () { return m_foo; }
private:
int m_foo;
};
这是一个采用Foo
对象的简单函数:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
这里是调用DoBar
函数的地方。
int main ()
{
DoBar (42);
}
参数不是Foo
对象,而是int
。但是,存在一个Foo
的构造函数,它接受一个int
因此可以使用此构造函数将参数转换为正确的类型。
允许编译器为每个参数执行一次此操作。
将explicit
关键字前缀到构造函数可防止编译器将该构造函数用于隐式转换。将它添加到上面的类将在函数调用DoBar (42)
创建编译器错误。现在需要使用DoBar (Foo (42))
明确调用转换DoBar (Foo (42))
您可能希望这样做的原因是为了避免可以隐藏错误的意外构造。举例:
MyString(int size)
类,它有一个构造函数,用于构造给定大小的字符串。你有一个函数print(const MyString&)
,并调用print(3)
当你真正用于调用print("3")
你希望它打印 “3”,但它打印一个长度为 3 的空字符串。 假设你有一个String
类:
class String {
public:
String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
现在,如果你尝试:
String mystring = 'x';
字符'x'
将隐式转换为int
,然后将调用String(int)
构造函数。但是,这不是用户可能想要的。因此,为了防止这种情况,我们将构造函数定义为explicit
:
class String {
public:
explicit String (int n); //allocate n bytes
String(const char *p); // initialize sobject with string p
};
在 C ++ 中,只有一个必需参数的构造函数被认为是隐式转换函数。它将参数类型转换为类类型。这是否是好事取决于构造函数的语义。
例如,如果你有一个带有构造函数String(const char* s)
的字符串类,那可能就是你想要的。您可以将const char*
传递给期望String
的函数,编译器将自动为您构造临时String
对象。
另一方面,如果你有一个缓冲类,其构造函数Buffer(int size)
占用缓冲区的大小(以字节为单位),你可能不希望编译器悄悄地将int
转换为Buffer
s。要防止这种情况,请使用explicit
关键字声明构造函数:
class Buffer { explicit Buffer(int size); ... }
那样,
void useBuffer(Buffer& buf);
useBuffer(4);
成为编译时错误。如果要传递临时Buffer
对象,则必须明确地执行此操作:
useBuffer(Buffer(4));
总之,如果您的单参数构造函数将参数转换为类的对象,您可能不希望使用explicit
关键字。但是如果你有一个只需要一个参数的构造函数,那么你应该将它声明为explicit
以防止编译器因意外的转换而让你感到惊讶。