为什么隐式转换在C++中是有害的

sky*_*oor 23 c++

我知道关键字explicit可用于防止隐式转换.

例如

Foo {

 public:
 explicit Foo(int i) {}
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,在什么条件下,应该禁止隐含转换?为什么隐式转换有害?

Bri*_*ndy 11

使用explicit时,你会喜欢一个编译错误.

explicit 仅当构造函数中有一个参数时才适用(或许多第一个参数只有没有默认值的参数).

你可能希望explicit在程序员错误地构造一个对象的任何时候使用该关键字,认为它可能会做一些它实际上没做的事情.

这是一个例子:

class MyString
{
public:
    MyString(int size)
        : size(size)
    {
    }

     //... other stuff

    int size;
};
Run Code Online (Sandbox Code Playgroud)

使用以下代码,您可以执行此操作:

int age = 29;
//...
//Lots of code
//...
//Pretend at this point the programmer forgot the type of x and thought string
str s = x;
Run Code Online (Sandbox Code Playgroud)

但是调用者可能意味着在MyString变量中存储"3"而不是3.最好得到一个编译错误,这样用户可以先调用itoa或x变量上的其他转换函数.

将为上述代码生成编译错误的新代码:

class MyString
{
public:
    explicit MyString(int size)
        : size(size)
    {
    }

     //... other stuff

    int size;
};
Run Code Online (Sandbox Code Playgroud)

编译错误总是优于错误,因为它们可以立即显示以供您更正.


Nik*_*sov 8

它引入了意想不到的临时工:

struct Bar
{
    Bar();      // default constructor
    Bar( int ); // value constructor with implicit conversion
};

void func( const Bar& );

Bar b;
b = 1; // expands to b.operator=( Bar( 1 ));
func( 10 ); // expands to func( Bar( 10 ));
Run Code Online (Sandbox Code Playgroud)

  • @Nikolai:实际上,这不是问题.C++中的所有东西都隐藏着昂贵的操作,例如重载的`operator +`.使用它的真正原因是当它做某事时,写作者可能没想到; 通过使用完整的语法,他们希望看起来或IDE将寻找它们 (4认同)
  • 因为这是意料之外的。该语法看起来像是将 b 设置为 1,但实际上它创建了一个新对象。它隐藏了真正发生的事情。http://blogs.msdn.com/oldnewthing/archive/2006/05/24/605974.aspx (2认同)

Tho*_*ini 5

一个现实世界的例子:

class VersionNumber
{
public:
    VersionNumber(int major, int minor, int patch = 0, char letter = '\0') : mMajor(major), mMinor(minor), mPatch(patch), mLetter(letter) {}
    explicit VersionNumber(uint32 encoded_version) { memcpy(&mLetter, &encoded_version, 4); }
    uint32 Encode() const { int ret; memcpy(&ret, &mLetter, 4); return ret; }

protected:
    char mLetter;
    uint8 mPatch;
    uint8 mMinor;
    uint8 mMajor;
};
Run Code Online (Sandbox Code Playgroud)

VersionNumber v = 10;几乎可以肯定是一个错误,所以explicit关键字需要程序员输入VersionNumber v(10);- 如果他或她使用一个体面的IDE - 他们会通过它想要的IntelliSense弹出窗口注意到encoded_version.