ctor:为什么'明确'防止任务建设?

时间:2014-06-24 07:41:00

标签: c++ constructor

我的课程ByteArray定义如下:

class ByteArray
{
public:
    explicit ByteArray( unsigned int uiSize = 0 );
    explicit ByteArray( const char * ucSource );
    ByteArray( const ByteArray & other );

    ByteArray & operator=( const char * ucSource );
    ByteArray & operator=( const ByteArray & other );
}

虽然几乎所有东西都有效但是通过赋值构造ByteArray不会编译。

ByteArray ba1( 5 );     // works
ByteArray ba2( ba1 );   // works
ByteArray ba3( "ABC" ); // works
ByteArray ba4;          // works
ba4 = "ABC";            // works
ByteArray ba5 = "ABC";  // <<<----- doesn't compile!

编译器给了我无法将'const char *'转换为'ByteArray'。
但是,“赋值构造函数”应该与复制构造函数相同,即。 ba5行应该像ba3行一样编译 - 与ba4的构造和后续赋值形成对比。所以,我不太确定编译器有什么问题。

我知道解决方法是删除第3个ctor前面的explicit。我宁愿先了解发生了什么,但是......

编辑:
答案很好地说明了:ByteArray ba5 = "ABC";将被编译为ByteArray ba5( ByteArray("ABC") ); ---而不是像我想象的那样ByteArray ba5("ABC");。很明显,但有时你需要有人指出来。谢谢大家的回答!

为什么要使用'明确'呢?因为unsigned intconst char *之间存在歧义。如果我调用ByteArray ba( 0 );两个ctors都能够处理,那么我需要禁止隐式转换并将其设为explicit

5 个答案:

答案 0 :(得分:9)

ByteArray ba5 = "ABC";是复制初始化,而不是赋值。

将其视为

ByteArray ba5(ByteArray("ABC"));

或者至少是编译器看到的内容。由于构造函数的explicit属性,它在您的情况下是非法的 - 编译器希望使用该转换构造函数来执行复制初始化,但它不能,因为您没有明确说明用它。

答案 1 :(得分:2)

如果您不使用显式关键字,则允许编译器使用构造函数将初始化使用=(复制初始化)转换为初始化。但有时您不希望出现此行为,因此您使用explicit关键字来避免此转化。所以你实际上得到了预期的结果。

可以使用显式构造函数限制的一些示例是

explicit T(const other_type &other);
T object = other;
f(other); // if f recieves object by value
return other;  // if function returns object by value
catch ( T other);
T array [ N ] = { other };

答案 2 :(得分:2)

C ++ 11 12.3.1 / 2&#34;由构造函数转换&#34;表示:

  

显式构造函数构造对象就像非显式构造函数一样,但仅这样,其中显式使用直接初始化语法(8.5)或强制转换(5.2.9,5.4)。 / p>

表格:

ByteArray ba5 = "ABC";

是复制初始化(每8.5 / 14),而不是直接初始化(ByteArray ba3( "ABC" ))(每8.5 / 15),因此不能使用显式构造函数。

答案 3 :(得分:1)

C ++有两种类型的初始化,复制初始化和 直接初始化。在复制初始化的情况下, 正式规则说应该使用复制构造函数;如果 表达式没有正确的类型,它将是 转换。 (允许编译器忽略额外的副本, 但它仍然必须确保代码是合法的,没有 eliding。)初始化由=符号表示(在...中) 这种情况是赋值运算符)使用副本 初始化,传递参数或返回 值,或抛出或捕获异常。该 用括号或括号标记的初始化(in C ++ 11)是直接初始化,初始化也是如此 new表达式,基数和成员初始化,以及 各种显式转换(static_cast等)。

对于实际作业,当然,规则是那些 一个函数调用(它就是这样 - 没有新变量 建造)。在您的情况下,ba4 = "ABC";因您而有效 有一个赋值运算符char const*;没有 隐式转换是必要的。

(虽然我在这里:我会在副本上避免explicit 构造函数。我不确定它到底意味着什么,我不是 确保其他任何人都是explicit的目的 是为了防止构造函数被隐式使用 转换,当然,不能使用复制构造函数 无论如何,在任何转换中。)

答案 4 :(得分:0)

到目前为止提供的答案可以让您深入了解为什么代码不起作用。但这不能解释为什么它不起作用。
复制初始化是初始化变量的一种方式。显式是一种确保在构造或分配中不发生隐式转换的方法。以我的经验,复制初始化始终与直接初始化具有相同的行为(尽管我不知道这是否可以保证)。 为什么“显式”存在会阻止复制初始化有效?或者,换一种方式来看,如何使副本初始化与显式构造函数一起使用?如果不可能,那么这肯定是语言规范中的一个缺陷-如果声明并定义了相关功能,启用它似乎没有任何不利之处。