显式关键字是什么意思?
C++ 中的 explicit
关键字是什么意思?
What does the explicit
keyword mean in C++?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
C++ 中的 explicit
关键字是什么意思?
What does the explicit
keyword mean in C++?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(11)
其他答案遗漏了我要在这里提到的一个重要因素。
与“delete”关键字一起,“explicit”允许您控制编译器生成特殊成员函数的方式 - 默认构造函数、复制构造函数、复制赋值运算符、析构函数、移动构造函数和移动赋值。
请参阅 https://learn.microsoft.com /en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions
Other answers are missing one important factor which I am going to mention here.
Along with "delete" keyword, "explicit" allows you to control the way compiler is going to generate special member functions - default constructor, copy constructor, copy-assignment operator, destructor, move constructor and move-assignment.
Refer https://learn.microsoft.com/en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions
允许编译器进行一次隐式转换来解析函数的参数。 这意味着编译器可以使用可通过单个参数调用的构造函数从一种类型转换为另一种类型,以获得参数的正确类型。
下面是一个转换构造函数的示例,展示了其工作原理:
在构造函数中添加
explicit
关键字可防止编译器使用该构造函数进行隐式转换。 将其添加到上面的类中将在函数调用bar(42)
处产生编译器错误。 现在需要使用bar(Foo(42))
显式调用转换。您可能想要这样做的原因是为了避免可能隐藏错误的意外构造。
人为示例:
MyString
类,其构造函数可以构造给定大小的字符串。 您有一个函数print(const MyString&)
(以及重载print (char *string)
),并且调用print(3)
code> (当您实际上打算调用print("3")
时)。 您希望它打印“3”,但它却打印出长度为 3 的空字符串。The compiler is allowed to make one implicit conversion to resolve the parameters to a function. This means that the compiler can use constructors callable with a single parameter to convert from one type to another in order to get the right type for a parameter.
Here's an example with converting constructors that shows how it works:
Prefixing the
explicit
keyword to the constructor prevents the compiler from using that constructor for implicit conversions. Adding it to the above class will create a compiler error at the function callbar(42)
. It is now necessary to call for conversion explicitly withbar(Foo(42))
The reason you might want to do this is to avoid accidental construction that can hide bugs.
Contrived example:
MyString
class with a constructor that constructs a string of the given size. You have a functionprint(const MyString&)
(as well as an overloadprint (char *string)
), and you callprint(3)
(when you actually intended to callprint("3")
). You expect it to print "3", but it prints an empty string of length 3 instead.假设您有一个类
String
:现在,如果您尝试:
字符
'x'
将隐式转换为int
,然后 < code>String(int) 构造函数将被调用。 但是,这可能不是用户想要的。 因此,为了防止出现这种情况,我们将构造函数定义为显式:Suppose, you have a class
String
:Now, if you try:
The character
'x'
will be implicitly converted toint
and then theString(int)
constructor will be called. But, this is not what the user might have intended. So, to prevent such conditions, we shall define the constructor asexplicit
:关键字
explicit
伴随概述
显式转换函数和构造函数只能用于显式转换(直接初始化或显式强制转换操作),而非显式构造函数和转换函数可用于隐式和显式转换。
使用结构体
X, Y, Z
和函数foo, bar, baz
的示例:让我们看一下结构体和函数的一个小设置,看看
explicit< 之间的区别/code> 和非显式转换。
有关构造函数的示例:
函数参数的转换:
对象初始化:
有关转换函数的示例:
函数参数的转换:
对象初始化:
为什么使用显式转换函数或构造函数?
转换构造函数和非显式转换函数可能会引入歧义。
考虑一个结构体
V
,可转换为int
,一个结构体U 可从
V
和分别为U
和bool
重载的函数f
隐式构造。如果传递
V
类型的对象,则对f
的调用是不明确的。编译器不知道是使用
U
的构造函数还是转换函数将V
对象转换为类型以传递给f
。如果
U
的构造函数或V
的转换函数是显式
,则不会有歧义,因为只有非显式转换才会发生予以考虑。 如果两者都是显式的,则必须使用显式转换或强制转换操作来使用V
类型的对象调用f
。转换构造函数和非显式转换函数可能会导致意外行为。
考虑一个打印某些向量的函数:
如果向量的大小构造函数不是显式的,则可以像这样调用该函数:
人们对这样的电话会期待什么? 一行包含
3
还是三行包含0
? (第二个就是发生的情况。)在类接口中使用显式关键字会强制接口的用户明确所需的转换。
正如 Bjarne Stroustrup 所说(在《C++ 编程语言》,第 4 版,35.2.1,第 1011 页)关于为什么
std::duration
不能从普通数字隐式构造的问题:The keyword
explicit
accompanies eitherOverview
Explicit conversion functions and constructors can only be used for explicit conversions (direct initialization or explicit cast operation) while non-explicit constructors and conversion functions can be used for implicit as well as explicit conversions.
Example using structures
X, Y, Z
and functionsfoo, bar, baz
:Let's look at a small setup of structures and functions to see the difference between
explicit
and non-explicit
conversions.Examples regarding constructor:
Conversion of a function argument:
Object initialization:
Examples regarding conversion functions:
Conversion of a function argument:
Object initialization:
Why use
explicit
conversion functions or constructors?Conversion constructors and non-explicit conversion functions may introduce ambiguity.
Consider a structure
V
, convertible toint
, a structureU
implicitly constructible fromV
and a functionf
overloaded forU
andbool
respectively.A call to
f
is ambiguous if passing an object of typeV
.The compiler does not know wether to use the constructor of
U
or the conversion function to convert theV
object into a type for passing tof
.If either the constructor of
U
or the conversion function ofV
would beexplicit
, there would be no ambiguity since only the non-explicit conversion would be considered. If both are explicit the call tof
using an object of typeV
would have to be done using an explicit conversion or cast operation.Conversion constructors and non-explicit conversion functions may lead to unexpected behaviour.
Consider a function printing some vector:
If the size-constructor of the vector would not be explicit it would be possible to call the function like this:
What would one expect from such a call? One line containing
3
or three lines containing0
? (Where the second one is what happens.)Using the explicit keyword in a class interface enforces the user of the interface to be explicit about a desired conversion.
As Bjarne Stroustrup puts it (in "The C++ Programming Language", 4th Ed., 35.2.1, pp. 1011) on the question why
std::duration
cannot be implicitly constructed from a plain number:在 C++ 中,只有一个必需参数的构造函数被视为隐式转换函数。 它将参数类型转换为类类型。 这是否是一件好事取决于构造函数的语义。
例如,如果您有一个带有构造函数
String(const char* s)
的字符串类,那么这可能正是您想要的。 您可以将const char*
传递给需要String
的函数,编译器将自动为您构造一个临时String
对象。另一方面,如果您有一个缓冲区类,其构造函数
Buffer(int size)
接受缓冲区大小(以字节为单位),您可能不希望编译器悄悄地将int< /code>s 到
Buffer
s 中。 为了防止这种情况,您可以使用explicit
关键字声明构造函数:这样,
就会出现编译时错误。 如果你想传递一个临时的 Buffer 对象,你必须明确地这样做:
总之,如果你的单参数构造函数将参数转换为你的类的对象,你可能不希望使用
explicit
关键字。 但是,如果您的构造函数恰好采用单个参数,则应该将其声明为显式,以防止编译器因意外转换而让您感到意外。In C++, a constructor with only one required parameter is considered an implicit conversion function. It converts the parameter type to the class type. Whether this is a good thing or not depends on the semantics of the constructor.
For example, if you have a string class with constructor
String(const char* s)
, that's probably exactly what you want. You can pass aconst char*
to a function expecting aString
, and the compiler will automatically construct a temporaryString
object for you.On the other hand, if you have a buffer class whose constructor
Buffer(int size)
takes the size of the buffer in bytes, you probably don't want the compiler to quietly turnint
s intoBuffer
s. To prevent that, you declare the constructor with theexplicit
keyword:That way,
becomes a compile-time error. If you want to pass a temporary
Buffer
object, you have to do so explicitly:In summary, if your single-parameter constructor converts the parameter into an object of your class, you probably don't want to use the
explicit
keyword. But if you have a constructor that simply happens to take a single parameter, you should declare it asexplicit
to prevent the compiler from surprising you with unexpected conversions.这个答案是关于使用/不使用显式构造函数的对象创建,因为其他答案中没有涵盖它。
考虑以下没有显式构造函数的类:
可以通过两种方式创建 Foo 类的对象:
根据实现的不同,实例化 Foo 类的第二种方式可能会令人困惑,或者不是程序员想要的。 在构造函数前添加
explicit
关键字会在Foo bar2 = 20;
处生成编译器错误。将单参数构造函数声明为
显式
通常是一种很好的做法,除非您的实现明确禁止这样做。另请注意,
的构造函数都可以用作单参数构造函数。 因此,您可能想让这些也变得
显式
。您故意不想要使单参数构造函数显式的一个例子是,如果您正在创建一个仿函数(查看 这个答案)。 在这种情况下,创建一个对象为
add_x add30 = 30;
可能是有意义的。这里是关于显式的很好的文章构造函数。
This answer is about object creation with/without an explicit constructor since it is not covered in the other answers.
Consider the following class without an explicit constructor:
Objects of class Foo can be created in 2 ways:
Depending upon the implementation, the second manner of instantiating class Foo may be confusing, or not what the programmer intended. Prefixing the
explicit
keyword to the constructor would generate a compiler error atFoo bar2 = 20;
.It is usually good practice to declare single-argument constructors as
explicit
, unless your implementation specifically prohibits it.Note also that constructors with
can both be used as single-argument constructors. So you may want to make these also
explicit
.An example when you would deliberately not want to make your single-argument constructor explicit is if you're creating a functor (look at the 'add_x' struct declared in this answer). In such a case, creating an object as
add_x add30 = 30;
would probably make sense.Here is a good write-up on explicit constructors.
explicit
关键字可用于强制显式调用构造函数。构造函数
C()
前面的explicit
关键字告诉编译器只允许显式调用此构造函数。explicit
- 关键字也可以用在用户定义的类型转换运算符中:这里,
explicit
- 关键字强制只有显式转换才有效,因此bool b =在这种情况下,c;
将是无效的转换。 在这些情况下,explicit
关键字可以帮助程序员避免隐式的、意外的强制转换。 此用法已在 C++11 中标准化。The
explicit
-keyword can be used to enforce a constructor to be called explicitly.the
explicit
-keyword in front of the constructorC()
tells the compiler that only explicit call to this constructor is allowed.The
explicit
-keyword can also be used in user-defined type cast operators:Here,
explicit
-keyword enforces only explicit casts to be valid, sobool b = c;
would be an invalid cast in this case. In situations like theseexplicit
-keyword can help programmer to avoid implicit, unintended casts. This usage has been standardized in C++11.explicit
关键字将转换构造函数转换为非转换构造函数。 因此,代码不易出错。The
explicit
keyword makes a conversion constructor to non-conversion constructor. As a result, the code is less error prone.Cpp 参考总是有帮助的! 有关显式说明符的详细信息可以在此处找到。 您可能需要查看隐式转换和复制初始化 也是如此。
快速查看
示例如下:
Cpp Reference is always helpful!!! Details about explicit specifier can be found here. You may need to look at implicit conversions and copy-initialization too.
Quick look
Example as follows:
如前所述,创建单参数构造函数(包括具有
arg2
、arg3
...默认值的构造函数)始终是一种良好的编码实践。与 C++ 一样:如果你不这样做 - 你会希望你这样做...
类的另一个好习惯是使复制构造和赋值私有(也称为禁用它),除非你确实需要实现它。 这可以避免在使用 C++ 默认为您创建的方法时最终产生指针副本。 另一种方法是从
boost::noncopyable
派生。It is always a good coding practice to make your one argument constructors (including those with default values for
arg2
,arg3
,...) as already stated.Like always with C++: if you don't - you'll wish you did...
Another good practice for classes is to make copy construction and assignment private (a.k.a. disable it) unless you really need to implement it. This avoids having eventual copies of pointers when using the methods that C++ will create for you by default. An other way to do this is derive from
boost::noncopyable
.构造函数附加隐式转换。 要抑制这种隐式转换,需要显式声明带有参数的构造函数。
在 C++11 中,您还可以使用关键字 http 指定“operator type()”: //en.cppreference.com/w/cpp/language/explicit 通过这样的规范,您可以在显式转换和对象的直接初始化方面使用运算符。
PS 当使用由用户定义的转换(通过构造函数和类型转换运算符)时,只允许使用一级隐式转换。
但是您可以将此转换与其他语言转换结合起来,
Constructors append implicit conversion. To suppress this implicit conversion it is required to declare a constructor with a parameter explicit.
In C++11 you can also specify an "operator type()" with such keyword http://en.cppreference.com/w/cpp/language/explicit With such specification you can use operator in terms of explicit conversions, and direct initialization of object.
P.S. When using transformations defined BY USER (via constructors and type conversion operator) it is allowed only one level of implicit conversions used.
But you can combine this conversions with other language conversions