C++ 显式关键字是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/121162/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:01:09  来源:igfitidea点击:

What does the explicit keyword mean?

c++constructorexplicitc++-faqexplicit-constructor

提问by Skizz

What does the explicitkeyword mean in C++?

explicitC++中的关键字是什么意思?

回答by Skizz

The compiler is allowed to make one implicit conversion to resolve the parameters to a function. What this means is that the compiler can use constructors callable with a single parameterto convert from one type to another in order to get the right type for a parameter.

允许编译器进行一次隐式转换以将参数解析为函数。这意味着编译器可以使用可通过单个参数调用的构造函数将一种类型转换为另一种类型,以便为参数获得正确的类型。

Here's an example class with a constructor that can be used for implicit conversions:

这是一个带有可用于隐式转换的构造函数的示例类:

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;
};

Here's a simple function that takes a Fooobject:

这是一个接受Foo对象的简单函数:

void DoBar (Foo foo)
{
  int i = foo.GetFoo ();
}

and here's where the DoBarfunction is called.

DoBar是调用函数的地方。

int main ()
{
  DoBar (42);
}

The argument is not a Fooobject, but an int. However, there exists a constructor for Foothat takes an intso this constructor can be used to convert the parameter to the correct type.

参数不是一个Foo对象,而是一个int. 然而,对于存在一个构造函数Foo,它接受一个int如此此构造可用于将参数转换为正确的类型。

The compiler is allowed to do this once for each parameter.

编译器可以为每个参数执行一次。

Prefixing the explicitkeyword 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 call DoBar (42). It is now necessary to call for conversion explicitly with DoBar (Foo (42))

explicit为构造函数添加关键字前缀可防止编译器使用该构造函数进行隐式转换。将它添加到上述类将在函数调用时产生编译器错误DoBar (42)。现在需要明确地调用转换 DoBar (Foo (42))

The reason you might want to do this is to avoid accidental construction that can hide bugs. Contrived example:

您可能想要这样做的原因是为了避免可能隐藏错误的意外构造。人为的例子:

  • You have a MyString(int size)class with a constructor that constructs a string of the given size. You have a function print(const MyString&), and you call print(3)(when you actuallyintended to call print("3")). You expect it to print "3", but it prints an empty string of length 3 instead.
  • 您有一个MyString(int size)带有构造函数的类,该类构造给定大小的字符串。你有一个函数print(const MyString&),你调用print(3)(当你真正打算调用时print("3"))。您希望它打印“3”,但它会打印一个长度为 3 的空字符串。

回答by Eddie

Suppose, you have a class String:

假设,你有一个类String

class String {
public:
    String(int n); // allocate n bytes to the String object
    String(const char *p); // initializes object with char *p
};

Now, if you try:

现在,如果您尝试:

String mystring = 'x';

The character 'x'will be implicitly converted to intand then the String(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 as explicit:

该字符'x'将被隐式转换为int,然后String(int)将调用构造函数。但是,这不是用户可能想要的。因此,为了防止出现这种情况,我们将构造函数定义为explicit

class String {
public:
    explicit String (int n); //allocate n bytes
    String(const char *p); // initialize sobject with string p
};

回答by cjm

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.

在 C++ 中,只有一个必需参数的构造函数被认为是隐式转换函数。它将参数类型转换为类类型。这是否是一件好事取决于构造函数的语义。

For example, if you have a string class with constructor String(const char* s), that's probably exactly what you want. You can pass a const char*to a function expecting a String, and the compiler will automatically construct a temporary Stringobject for you.

例如,如果您有一个带构造函数的字符串类String(const char* s),那可能正是您想要的。您可以将 a 传递给const char*需要 a 的函数String,编译器会自动String为您构造一个临时对象。

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 turn ints into Buffers. To prevent that, you declare the constructor with the explicitkeyword:

另一方面,如果您有一个缓冲区类,其构造函数Buffer(int size)以字节为单位获取缓冲区的大小,您可能不希望编译器悄悄地将ints 转换为Buffers。为了防止这种情况,您可以使用explicit关键字声明构造函数:

class Buffer { explicit Buffer(int size); ... }

That way,

那样,

void useBuffer(Buffer& buf);
useBuffer(4);

becomes a compile-time error. If you want to pass a temporary Bufferobject, you have to do so explicitly:

成为编译时错误。如果你想传递一个临时Buffer对象,你必须明确地这样做:

useBuffer(Buffer(4));

In summary, if your single-parameter constructor converts the parameter into an object of your class, you probably don't want to use the explicitkeyword. But if you have a constructor that simply happens to take a single parameter, you should declare it as explicitto prevent the compiler from surprising you with unexpected conversions.

总之,如果您的单参数构造函数将参数转换为您的类的对象,您可能不想使用explicit关键字。但是,如果您的构造函数恰好采用单个参数,则应声明它explicit以防止编译器以意外的转换使您感到惊讶。

回答by coding_ninza

Explicit conversion constructors (C++ only)

显式转换构造函数(仅限 C++)

The explicit function specifier controls unwanted implicit type conversions. It can only be used in declarations of constructors within a class declaration. For example, except for the default constructor, the constructors in the following class are conversion constructors.

显式函数说明符控制不需要的隐式类型转换。它只能在类声明中的构造函数声明中使用。例如,除默认构造函数外,以下类中的构造函数均为转换构造函数。

class A
{
public:
    A();
    A(int);
    A(const char*, int = 0);
};

The following declarations are legal:

以下声明是合法的:

A c = 1;
A d = "Venditti";

The first declaration is equivalent to A c = A( 1 );.

第一个声明等效于A c = A( 1 );.

If you declare the constructor of the class as explicit, the previous declarations would be illegal.

如果将类的构造函数声明为explicit,则先前的声明将是非法的。

For example, if you declare the class as:

例如,如果您将类声明为:

class A
{
public:
    explicit A();
    explicit A(int);
    explicit A(const char*, int = 0);
};

You can only assign values that match the values of the class type.

您只能分配与类类型的值匹配的值。

For example, the following statements are legal:

例如,以下语句是合法的:

  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);

回答by Gautam

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:

考虑以下没有显式构造函数的类:

class Foo
{
public:
    Foo(int x) : m_x(x)
    {
    }

private:
    int m_x;
};

Objects of class Foo can be created in 2 ways:

Foo 类的对象可以通过两种方式创建:

Foo bar1(10);

Foo bar2 = 20;

Depending upon the implementation, the second manner of instantiating class Foo may be confusing, or not what the programmer intended. Prefixing the explicitkeyword to the constructor would generate a compiler error at Foo bar2 = 20;.

根据实现,实例化类 Foo 的第二种方式可能会令人困惑,或者不是程序员的意图。explicit为构造函数添加关键字前缀会在 处生成编译器错误Foo bar2 = 20;

It is usuallygood practice to declare single-argument constructors as explicit, unless your implementation specifically prohibits it.

通常将单参数构造函数声明为是一种很好的做法explicit,除非您的实现明确禁止它。

Note also that constructors with

还要注意构造函数

  • default arguments for all parameters, or
  • default arguments for the second parameter onwards
  • 所有参数的默认参数,或
  • 第二个参数的默认参数

can both be used as single-argument constructors. So you may want to make these also explicit.

两者都可以用作单参数构造函数。所以你可能也想制作这些explicit

An example when you would deliberately notwant to make your single-argument constructor explicit is if you're creating a functor (look at the 'add_x' struct declared in thisanswer). In such a case, creating an object as add_x add30 = 30;would probably make sense.

当你会故意的例子并不想使你的单参数的构造函数明确的是,如果你正在创建一个仿函数(看“ADD_X”结构中声明这个答案)。在这种情况下,创建对象 asadd_x add30 = 30;可能是有意义的。

Hereis a good write-up on explicit constructors.

是关于显式构造函数的一篇很好的文章。

回答by Pixelchemist

The keyword explicitaccompanies either

关键字explicit伴随着

  • a constructor of class X that cannot be used to implicitly convert the first (any only) parameter to type X
  • 不能用于将第一个(任何唯一)参数隐式转换为类型 X 的 X 类构造函数

C++ [class.conv.ctor]

1) A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

2) An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or valueinitialization (8.5).

C++ [class.conv.ctor]

1) 没有函数说明符显式声明的构造函数指定了从其参数类型到其类类型的转换。这样的构造函数称为转换构造函数。

2) 显式构造函数像非显式构造函数一样构造对象,但仅在显式使用直接初始化语法 (8.5) 或强制转换 (5.2.9, 5.4) 的地方这样做。默认构造函数可以是显式构造函数;这样的构造函数将用于执行默认初始化或值初始化(8.5)。

  • or a conversion function that is only considered for direct initialization and explicit conversion.
  • 或仅考虑用于直接初始化和显式转换的转换函数。

C++ [class.conv.fct]

2) A conversion function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5). Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

C++ [class.conv.fct]

2) 转换函数可以是显式的 (7.1.2),在这种情况下,它仅被视为用于直接初始化 (8.5) 的用户定义转换。否则,用户定义的转换不限于在赋值和初始化中使用。

Overview

概述

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.

显式转换函数和构造函数只能用于显式转换(直接初始化或显式转换操作),而非显式构造函数和转换函数可用于隐式和显式转换。

/*
                                 explicit conversion          implicit conversion

 explicit constructor                    yes                          no

 constructor                             yes                          yes

 explicit conversion function            yes                          no

 conversion function                     yes                          yes

*/

Example using structures X, Y, Zand functions foo, bar, baz:

使用结构X, Y, Z和函数的示例foo, bar, baz

Let's look at a small setup of structures and functions to see the difference between explicitand non-explicitconversions.

让我们看一下结构和函数的小设置,以了解转换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) { }

Examples regarding constructor:

关于构造函数的例子:

Conversion of a function argument:

函数参数的转换:

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

Object initialization:

对象初始化:

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

Examples regarding conversion functions:

有关转换函数的示例:

X x1{ 0 };
Y y1{ 0 };

Conversion of a function argument:

函数参数的转换:

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

Object initialization:

对象初始化:

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

Why use explicitconversion functions or constructors?

为什么要使用explicit转换函数或构造函数?

Conversion constructors and non-explicit conversion functions may introduce ambiguity.

转换构造函数和非显式转换函数可能会引入歧义。

Consider a structure V, convertible to int, a structure Uimplicitly constructible from Vand a function foverloaded for Uand boolrespectively.

考虑一个V可转换为int的结构、一个可U隐式构造自的结构V和一个分别fU和重载的函数bool

struct V {
  operator bool() const { return true; }
};

struct U { U(V) { } };

void f(U) { }
void f(bool) {  }

A call to fis ambiguous if passing an object of type V.

f如果传递类型为 的对象,则对 的调用是不明确的V

V x;
f(x);  // error: call of overloaded 'f(V&)' is ambiguous

The compiler does not know wether to use the constructor of Uor the conversion function to convert the Vobject into a type for passing to f.

编译器不知道是使用 的构造函数U还是转换函数将V对象转换为传递给 的类型f

If either the constructor of Uor the conversion function of Vwould be explicit, there would be no ambiguity since only the non-explicit conversion would be considered. If both are explicit the call to fusing an object of type Vwould have to be done using an explicit conversion or cast operation.

如果是在建构U或转换功能Vexplicit,将不会有歧义,因为只有非显式转换将被考虑。如果两者都是显式的,则必须使用显式转换或强制转换操作来调用f使用类型的对象V

Conversion constructors and non-explicit conversion functions may lead to unexpected behaviour.

转换构造函数和非显式转换函数可能会导致意外行为。

Consider a function printing some vector:

考虑一个打印一些向量的函数:

void print_intvector(std::vector<int> const &v) { for (int x : v) std::cout << x << '\n'; }

If the size-constructor of the vector would not be explicit it would be possible to call the function like this:

如果向量的大小构造函数不是明确的,则可以像这样调用函数:

print_intvector(3);

What would one expect from such a call? One line containing 3or three lines containing 0? (Where the second one is what happens.)

人们会从这样的电话中期待什么?一行包含3或三行包含0? (第二个是发生了什么。)

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::durationcannot be implicitly constructed from a plain number:

正如 Bjarne Stroustrup 所说(在“C++ 编程语言”,第 4 版,35.2.1,第 1011 页)关于为什么std::duration不能从一个普通数字隐式构造的问题:

If you know what you mean, be explicit about it.

如果您知道自己的意思,请明确说明。

回答by SankararaoMajji

The explicitkeyword makes a conversion constructor to non-conversion constructor. As a result, the code is less error prone.

explicit关键字使一个转换构造函数不变换的构造。因此,代码不易出错。

回答by Helixirr

The explicit-keyword can be used to enforce a constructor to be called explicitly.

explicit-keyword可以用来强制执行构造函数被调用明确

class C{
public:
    explicit C(void) = default;
};

int main(void){
    C c();
    return 0;
}

the explicit-keyword in front of the constructor C(void)tells the compiler that only explicit call to this constructor is allowed.

explicit构造函数前面的-keywordC(void)告诉编译器只允许显式调用这个构造函数。

The explicit-keyword can also be used in user-defined type cast operators:

所述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;
}

Here, explicit-keyword enforces only explicit casts to be valid, so bool b = c;would be an invalid cast in this case. In situations like these explicit-keyword can help programmer to avoid implicit, unintended casts. This usage has been standardized in C++11.

在这里,explicit-keyword 仅强制显式转换有效,因此bool b = c;在这种情况下将是无效转换。在这些情况下explicit-keyword 可以帮助程序员避免隐式的、意外的强制转换。这种用法已在C++11 中标准化。

回答by selfboot

Cpp Reference is always helpful!!! Details about explicit specifier can be found here. You may need to look at implicit conversionsand copy-initializationtoo.

Cpp 参考总是有帮助的!!!可以在此处找到有关显式说明符的详细信息。您可能还需要查看隐式转换复制初始化

Quick look

快速浏览

The explicit specifier specifies that a constructor or conversion function (since C++11) doesn't allow implicit conversions or copy-initialization.

显式说明符指定构造函数或转换函数 (C++11 起)不允许隐式转换或复制初始化。

Example as follows:

示例如下:

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
}

回答by fmuecke

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...

如前所述,使您的单参数构造函数(包括具有arg2, arg3,... 的默认值的构造函数)始终是一种很好的编码实践。就像 C++ 一样:如果你不这样做 - 你会希望你做到了......

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++ 默认为您创建的方法时最终会复制指针。另一种方法是从boost::noncopyable.