什么是明确关键词的意思吗?
-
02-07-2019 - |
题
是什么 explicit
关键词的意思是用C++?
解决方案
编译是允许做的一个隐性转换,以解决参数的一个函数。这意味着什么,是那个编译器可以使用的构造可调用的一个 单参数 把从一种类型,另一种为了得到正确类型为一个参数。
这里有一个例子类的构造,可用于隐性转换:
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
。为防止这种情况,请使用 explicit
关键字声明构造函数:
class Buffer { explicit Buffer(int size); ... }
那样,
void useBuffer(Buffer& buf);
useBuffer(4);
成为编译时错误。如果要传递临时的 Buffer
对象,则必须明确地执行此操作:
useBuffer(Buffer(4));
总之,如果您的单参数构造函数将参数转换为类的对象,您可能不希望使用 explicit
关键字。但是如果你有一个只需要一个参数的构造函数,那么你应该将它声明为 explicit
,以防止编译器因意外的转换而让你感到惊讶。
这个答案是有关对象的创作/没有一个明确的构造,因为它没有复盖的其他答复。
请考虑以下类没有一个明确的构造:
class Foo
{
public:
Foo(int x) : m_x(x)
{
}
private:
int m_x;
};
目的class Foo可以建立在2种方式:
Foo bar1(10);
Foo bar2 = 20;
根据执行情况,第二种方式的实例,class Foo可能会造成混乱,或者没有什么程序的目的。前缀 explicit
关键字的构造将生成一个编译器错误 Foo bar2 = 20;
.
它是 通常 良好做法宣布的单参数的构造作 explicit
, 除非您的执行具体的禁止。
还注意到,与构造
- 缺省参数,为所有参数,或
- 缺省参数,第二个参数开始
都可以被用作为单参数的构造.所以,你可能想要使这些也 explicit
.
一个例子的时候你会故意 不 想让你的单参数的构造方法明确的是如果你正在创建一个函(来看看'add_x'结构中声明 此 回答).在这样的情况下,创建一个对象 add_x add30 = 30;
可能会有意义。
在这里, 是一个很好写了明确的构造方法。
explicit
关键字使转换构造函数成为非转换构造函数。因此,代码不易出错。
关键字 explicit
伴随着无论哪
- 一个构造的X类,不能被用来隐含地将第(任何)的参数类型X
C++[类。conv.构造函数]
1)一个构造宣布,而不能说明符的明确指定一个转换的类型参数据的类型。这样的构造是所谓的一个转换的构造。
2)一个明确的构造结构的对象,就像非明确的构造,但这样做只有在直接的初始化法(8.5)或蒙上(5.2.9,5.4)明确使用。默认的构造可将一个明确的构造;这样的一个构造将用于执行默认初始化或valueinitialization (8.5).
- 或者转换功能,只考虑直接的初始化和明确的转换。
C++[类。conv.fct]
2)一个转换功能的可以是明确的(7.1.2),在这种情况下,它只被视为用户定义转化为直接的初始化(8.5).否则,用户定义的转换并不限于使用在分配 和初始化。
概述
明确转换的职能和构造只能用于明确转化(直接的初始化或明确的投操作的),而非明确的构造和转换功能可用于隐性以及显的转换。
/*
explicit conversion implicit conversion
explicit constructor yes no
constructor yes yes
explicit conversion function yes no
conversion function yes yes
*/
例使用的结构 X, Y, Z
和职能 foo, bar, baz
:
让我们看看一个小设置的结构和功能看到差别 explicit
并非explicit
转换。
struct Z { };
struct X {
explicit X(int a); // X can be constructed from int explicitly
explicit operator Z (); // X can be converted to Z explicitly
};
struct Y{
Y(int a); // int can be implicitly converted to Y
operator Z (); // Y can be implicitly converted to Z
};
void foo(X x) { }
void bar(Y y) { }
void baz(Z z) { }
实例有关的构造:
转换功能的论点:
foo(2); // error: no implicit conversion int to X possible
foo(X(2)); // OK: direct initialization: explicit conversion
foo(static_cast<X>(2)); // OK: explicit conversion
bar(2); // OK: implicit conversion via Y(int)
bar(Y(2)); // OK: direct initialization
bar(static_cast<Y>(2)); // OK: explicit conversion
目初始化:
X x2 = 2; // error: no implicit conversion int to X possible
X x3(2); // OK: direct initialization
X x4 = X(2); // OK: direct initialization
X x5 = static_cast<X>(2); // OK: explicit conversion
Y y2 = 2; // OK: implicit conversion via Y(int)
Y y3(2); // OK: direct initialization
Y y4 = Y(2); // OK: direct initialization
Y y5 = static_cast<Y>(2); // OK: explicit conversion
实例有关于转换功能:
X x1{ 0 };
Y y1{ 0 };
转换功能的论点:
baz(x1); // error: X not implicitly convertible to Z
baz(Z(x1)); // OK: explicit initialization
baz(static_cast<Z>(x1)); // OK: explicit conversion
baz(y1); // OK: implicit conversion via Y::operator Z()
baz(Z(y1)); // OK: direct initialization
baz(static_cast<Z>(y1)); // OK: explicit conversion
目初始化:
Z z1 = x1; // error: X not implicitly convertible to Z
Z z2(x1); // OK: explicit initialization
Z z3 = Z(x1); // OK: explicit initialization
Z z4 = static_cast<Z>(x1); // OK: explicit conversion
Z z1 = y1; // OK: implicit conversion via Y::operator Z()
Z z2(y1); // OK: direct initialization
Z z3 = Z(y1); // OK: direct initialization
Z z4 = static_cast<Z>(y1); // OK: explicit conversion
为什么使用 explicit
转换的职能或构造?
转换的构造和非明确转换功能,可以介绍的模糊性。
考虑一个结构 V
, ,可转换为 int
, 结构 U
隐含地从可构造 V
和一个功能 f
载于 U
和 bool
分别。
struct V {
operator bool() const { return true; }
};
struct U { U(V) { } };
void f(U) { }
void f(bool) { }
一个呼叫 f
是模糊的,如果通过一个目的类型 V
.
V x;
f(x); // error: call of overloaded 'f(V&)' is ambiguous
编译器不知道是否使用的构造 U
或者转换功能转换 V
对象为的类型过来 f
.
如果该构造的 U
或者转换功能的 V
将会是 explicit
, 不会有歧义,因为只有非明确转换会议。如果两者都明确呼叫 f
使用对象的类型 V
必须使用一个明确转换或投的操作。
转换的构造和非明确转换功能可能会导致意想不到的行为。
考虑一个功能印刷一些矢量:
void print_intvector(std::vector<int> const &v) { for (int x : v) std::cout << x << '\n'; }
如果大小的构造的矢量将不是明确的,它将有可能通话的功能,像这样:
print_intvector(3);
什么将一个预期从这样的话吗?一个包含 3
或含有三条线 0
?(在那里,第二个是会发生什么情况。)
使用明确的关键词一类的界面实行用户接口是明确关于所期望的转换。
作为Bjarne Stroustrup把它放(在"C++编程语言",4th Ed., 35.2.1,pp.1011)的问题为什么 std::duration
不能含蓄地建造一个普通的数量:
如果你知道你是什么意思,是明确的。
显式转换构造函数(仅限C ++)
显式函数说明符控制不需要的隐式类型 转换。它只能用于构造函数的声明 在一个类声明中。例如,默认值除外 构造函数,以下类中的构造函数是转换 构造
class A
{
public:
A();
A(int);
A(const char*, int = 0);
};
以下声明是合法的:
A c = 1;
A d = "Venditti";
第一个声明等同于 A c = A(1);
。
如果将类的构造函数声明为 explicit
,则先前的声明将是非法的。
例如,如果您将类声明为:
class A
{
public:
explicit A();
explicit A(int);
explicit A(const char*, int = 0);
};
您只能指定与类类型值匹配的值。
例如,以下陈述是合法的:
A a1;
A a2 = A(1);
A a3(1);
A a4 = A("Venditti");
A* p = new A(1);
A a5 = (A)1;
A a6 = static_cast<A>(1);
explicit
-keyword可用于强制构造函数显式 。
class C{
public:
explicit C(void) = default;
};
int main(void){
C c();
return 0;
}
构造函数前面的显式
- 关键字 C(void)
告诉编译器只允许显式调用此构造函数。
explicit
-keyword也可用于用户定义的类型转换操作符:
class C{
public:
explicit inline operator bool(void) const{
return true;
}
};
int main(void){
C c;
bool b = static_cast<bool>(c);
return 0;
}
此处, explicit
-keyword仅强制显式强制转换为有效,因此 bool b = c;
在这种情况下将是无效的强制转换。在这些情况下, explicit
-keyword可以帮助程序员避免隐式的,非预期的强制转换。此用法已在 C ++ 11 中标准化。
Cpp参考总是很有用!!!有关显式说明符的详细信息,请访问此处。您可能需要查看隐式转换和复制初始化。
快速浏览
显式说明符指定构造函数或转换函数(自C ++ 11以来)不允许隐式转换或复制初始化。
示例如下:
struct A
{
A(int) { } // converting constructor
A(int, int) { } // converting constructor (C++11)
operator bool() const { return true; }
};
struct B
{
explicit B(int) { }
explicit B(int, int) { }
explicit operator bool() const { return true; }
};
int main()
{
A a1 = 1; // OK: copy-initialization selects A::A(int)
A a2(2); // OK: direct-initialization selects A::A(int)
A a3 {4, 5}; // OK: direct-list-initialization selects A::A(int, int)
A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
A a5 = (A)1; // OK: explicit cast performs static_cast
if (a1) cout << "true" << endl; // OK: A::operator bool()
bool na1 = a1; // OK: copy-initialization selects A::operator bool()
bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization
// B b1 = 1; // error: copy-initialization does not consider B::B(int)
B b2(2); // OK: direct-initialization selects B::B(int)
B b3 {4, 5}; // OK: direct-list-initialization selects B::B(int, int)
// B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int,int)
B b5 = (B)1; // OK: explicit cast performs static_cast
if (b5) cout << "true" << endl; // OK: B::operator bool()
// bool nb1 = b2; // error: copy-initialization does not consider B::operator bool()
bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization
}
这已经讨论过(什么是显式构造函数)。但我必须说,它缺乏这里的详细描述。
此外,如上所述,使用一个参数构造函数(包括那些具有arg2,arg3,...的默认值的构造函数)总是一个很好的编码实践。 和C ++一样:如果你不这样做 - 你会希望你做到......
类的另一个好习惯是将复制构造和赋值设置为私有(a.k.a.禁用它),除非你真的需要实现它。这避免了在使用C ++默认为您创建的方法时最终有指针副本。另一种方法是从boost :: noncopyable派生。
造附加的隐性转换。来抑制这种隐性转换,它需要宣布一个构造与一个参数的明确的。
C++11还可以指定一个"经营者的类型()"与这样的关键字 http://en.cppreference.com/w/cpp/language/explicit 与这种规范可以使用的操作方面的明确转换和直接的初始化的对象。
P.S.当使用转换定义的用户(通过构造和类型转换操作员)允许只有一个等级的隐性转换使用。但你可以把这个转换用其他语言的转换
- 达组成的队伍(char int、浮到双);
- 标准转换(int双);
- 转换指针的对象,基类和void*;