我的课程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 int
和const char *
之间存在歧义。如果我调用ByteArray ba( 0 );
两个ctors都能够处理,那么我需要禁止隐式转换并将其设为explicit
。
答案 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)
到目前为止提供的答案可以让您深入了解为什么代码不起作用。但这不能解释为什么它不起作用。
复制初始化是初始化变量的一种方式。显式是一种确保在构造或分配中不发生隐式转换的方法。以我的经验,复制初始化始终与直接初始化具有相同的行为(尽管我不知道这是否可以保证)。
为什么“显式”存在会阻止复制初始化有效?或者,换一种方式来看,如何使副本初始化与显式构造函数一起使用?如果不可能,那么这肯定是语言规范中的一个缺陷-如果声明并定义了相关功能,启用它似乎没有任何不利之处。