显式关键字是什么意思?
C ++中explicit
关键字的含义是什么?
允许编译器进行一次隐式转换以将参数解析为一个函数。 这意味着编译器可以使用可用单个参数调用的构造函数将一种类型转换为另一种类型,以便为参数获取正确的类型。
下面是一个带有可用于隐式转换的构造函数的示例类:
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))
您可能想要这样做的原因是为了避免可能隐藏错误的意外构造。 受影响的例子:
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
以防止编译器意外地转换你的意外。