"explicit"关键字是什么意思?
假设你有一个类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 };
编译器允许进行一次隐式转换以解决函数参数的类型。这意味着编译器可以使用一个接受单个参数的构造函数来将一个类型转换为另一个类型,以便得到正确的参数类型。\n\n以下是一个具有可用于隐式转换的构造函数的示例类:\n\n
class Foo { private: int m_foo; public: // single parameter constructor, can be used as an implicit conversion Foo (int foo) : m_foo (foo) {} int GetFoo () { return m_foo; } };
\n\n以下是一个简单的需要一个Foo
对象参数的函数:\n\n
void DoBar (Foo foo) { int i = foo.GetFoo (); }
\n\n以下是调用DoBar
函数的地方:\n\n
int main () { DoBar (42); }
\n\n参数并不是一个Foo
对象,而是一个int
。然而,Foo
类有一个接受int
的构造函数,因此可以使用此构造函数将参数转换为正确的类型。\n\n编译器允许每个参数进行一次这样的操作。\n\n在构造函数前加上explicit
关键字可以防止编译器使用该构造函数进行隐式转换。在上面的类中添加这个关键字会在函数调用DoBar(42)
时创建编译器错误。现在需要显式调用转换,如DoBar(Foo(42))
。\n\n你可能想这样做是为了避免意外的构建,这可能会隐藏错误。\n\n假设示例:\n\n
- \n
- 你有一个
MyString
类,它有一个构造函数,用于构造给定大小的字符串。你有一个print(const MyString&)
函数(以及一个重载print(char * string)
),你调用print(3)
(当实际上你想调用print(“3”)
)。你期望它打印“3”,但它打印一个长度为3的空字符串。
\n