显式关键字是什么意思?

发布于 2024-07-06 03:16:07 字数 45 浏览 12 评论 0原文

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

What does the explicit keyword mean in C++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

靑春怀旧 2024-07-13 03:16:07

其他答案遗漏了我要在这里提到的一个重要因素。

与“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

无声静候 2024-07-13 03:16:07

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

下面是一个转换构造函数的示例,展示了其工作原理:

struct Foo {
    // Single parameter constructor, can be used as an implicit conversion.
    // Such a constructor is called "converting constructor".
    Foo(int x) {}
};
struct Faz {
    // Also a converting constructor.
    Faz(Foo foo) {}
};

// The parameter is of type Foo, not of type int, so it looks like
// we have to pass a Foo.
void bar(Foo foo) {};

int main() {
    // However, the converting constructor allows us to pass an int.
    bar(42);
    // Also allowed thanks to the converting constructor.
    Foo foo = 42;
    // Error! This would require two conversions (int -> Foo -> Faz).
    Faz faz = 42;
}

在构造函数中添加 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:

struct Foo {
    // Single parameter constructor, can be used as an implicit conversion.
    // Such a constructor is called "converting constructor".
    Foo(int x) {}
};
struct Faz {
    // Also a converting constructor.
    Faz(Foo foo) {}
};

// The parameter is of type Foo, not of type int, so it looks like
// we have to pass a Foo.
void bar(Foo foo) {};

int main() {
    // However, the converting constructor allows us to pass an int.
    bar(42);
    // Also allowed thanks to the converting constructor.
    Foo foo = 42;
    // Error! This would require two conversions (int -> Foo -> Faz).
    Faz faz = 42;
}

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 call bar(42). It is now necessary to call for conversion explicitly with bar(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 class with a constructor that constructs a string of the given size. You have a function print(const MyString&) (as well as an overload print (char *string)), and you call print(3) (when you actually intended to call print("3")). You expect it to print "3", but it prints an empty string of length 3 instead.
决绝 2024-07-13 03:16:07

假设您有一个类 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,然后 < code>String(int) 构造函数将被调用。 但是,这可能不是用户想要的。 因此,为了防止出现这种情况,我们将构造函数定义为显式:

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

Suppose, you have a class 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 int and 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:

class String {
public:
    explicit String (int n); //allocate n bytes
    String(const char *p); // initialize sobject with string p
};
风和你 2024-07-13 03:16:07

关键字 explicit 伴随

  • 类 X 的构造函数,该构造函数不能用于将第一个(任何唯一)参数隐式转换为类型 X

C++ [class.conv.ctor]

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

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

  • 或仅考虑直接初始化和显式转换的转换函数。

C++ [class.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< 之间的区别/code> 和非显式转换。

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

为什么使用显式转换函数或构造函数?

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

考虑一个结构体V,可转换为int,一个结构体U 可从 V 和分别为 Ubool 重载的函数 f 隐式构造。

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

struct U { U(V) { } };

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

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

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

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

如果 U 的构造函数或 V 的转换函数是显式,则不会有歧义,因为只有非显式转换才会发生予以考虑。 如果两者都是显式的,则必须使用显式转换或强制转换操作来使用 V 类型的对象调用 f

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

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

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

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

print_intvector(3);

人们对这样的电话会期待什么? 一行包含 3 还是三行包含 0? (第二个就是发生的情况。)

在类接口中使用显式关键字会强制接口的用户明确所需的转换。

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

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

The keyword explicit accompanies either

  • a constructor of class X that cannot be used to implicitly convert the first (any only) parameter to type 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).

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

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, Z and functions foo, bar, baz:

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

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 explicit conversion functions or constructors?

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

Consider a structure V, convertible to int, a structure U implicitly constructible from V and a function f overloaded for U and bool respectively.

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

struct U { U(V) { } };

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

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

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

The compiler does not know wether to use the constructor of U or the conversion function to convert the V object into a type for passing to f.

If either the constructor of U or the conversion function of V would be explicit, there would be no ambiguity since only the non-explicit conversion would be considered. If both are explicit the call to f using an object of type V 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:

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 3 or three lines containing 0? (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:

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

稍尽春風 2024-07-13 03:16:07

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

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

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

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

这样,

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

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

useBuffer(Buffer(4));

总之,如果你的单参数构造函数将参数转换为你的类的对象,你可能不希望使用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 a const char* to a function expecting a String, and the compiler will automatically construct a temporary String 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 turn ints into Buffers. To prevent that, you declare the constructor with the explicit keyword:

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 Buffer object, you have to do so explicitly:

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 explicit keyword. But if you have a constructor that simply happens to take a single parameter, you should declare it as explicit to prevent the compiler from surprising you with unexpected conversions.

夏末染殇 2024-07-13 03:16:07

这个答案是关于使用/不使用显式构造函数的对象创建,因为其他答案中没有涵盖它。

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

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

private:
    int m_x;
};

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

Foo bar1(10);

Foo bar2 = 20;

根据实现的不同,实例化 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:

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

private:
    int m_x;
};

Objects of class Foo can be created in 2 ways:

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 explicit keyword to the constructor would generate a compiler error at Foo 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

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

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.

天荒地未老 2024-07-13 03:16:07

explicit 关键字可用于强制显式调用构造函数。

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

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

构造函数 C() 前面的 explicit 关键字告诉编译器只允许显式调用此构造函数。

explicit - 关键字也可以用在用户定义的类型转换运算符中:

class C{
public:
    explicit inline operator bool() const {
        return true;
    }
};

int main() {
    C c;
    bool b = static_cast<bool>(c);
    return 0;
}

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

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

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

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

the explicit-keyword in front of the constructor C() 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:

class C{
public:
    explicit inline operator bool() const {
        return true;
    }
};

int main() {
    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.

抱猫软卧 2024-07-13 03:16:07

explicit 关键字将转换构造函数转换为非转换构造函数。 因此,代码不易出错。

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

三生殊途 2024-07-13 03:16:07

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
}

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

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

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
}
梦纸 2024-07-13 03:16:07

如前所述,创建单参数构造函数(包括具有 arg2arg3...默认值的构造函数)始终是一种良好的编码实践。
与 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.

你在我安 2024-07-13 03:16:07

构造函数附加隐式转换。 要抑制这种隐式转换,需要显式声明带有参数的构造函数。

在 C++11 中,您还可以使用关键字 http 指定“operator type()”: //en.cppreference.com/w/cpp/language/explicit 通过这样的规范,您可以在显式转换和对象的直接初始化方面使用运算符。

PS 当使用由用户定义的转换(通过构造函数和类型转换运算符)时,只允许使用一级隐式转换。
但是您可以将此转换与其他语言转换结合起来,

  • 提高整数级别(char 到 int、float 到 double);
  • 标准转换(int 到 double);
  • 将对象指针转换为基类和 void*;

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

  • up integral ranks (char to int, float to double);
  • standart conversions (int to double);
  • convert pointers of objects to base class and to void*;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文