为什么在第二次调用构造函数时删除了初始化成员变量?
示例:
class MyClass {
private:
unsigned myValue;
public:
MyClass(void)
{
this->myValue = 1337;
fprintf(stderr, "myValue: %d\n", this->myValue);
}
MyClass(int myFirstValue)
{
fprintf(stderr, "myValue: %d\n", this->myValue);
}
};
int main()
{
/* Constructor is called */
MyClass myInstance;
/* Call other constructor ; myInstance->myValue is now trashed */
myInstance = 100;
return 0;
}
输出:
myValue: 1337
myValue: 1606416392
预期产出:
myValue: 1337
myValue: 1337
有没有办法保留初始化成员变量?
答案 0 :(得分:5)
当你这样做时
myInstance = 100;
使用构造函数MyClass
在RHS上构造临时MyClass(int)
。然后使用临时值为LHS分配值。
该构造函数不初始化成员变量。读取未初始化的成员会导致未定义的行为,在您的情况下,这似乎会导致打印垃圾值。
因此,您需要初始化它,假设您要将成员初始化为构造函数中传递的值:
MyClass(int myFirstValue) : myValue(myFirstValue)
{
// as before
}
修改,因为您希望该成员的值为1337
,您需要
MyClass(int myFirstValue) : myValue(1337) { .... }
答案 1 :(得分:1)
myInstance = 100;
是对函数MyClass& MyClass::operator=( MyClass const &other)
但是因为你没有实现它,所以调用默认赋值运算符。如您所见,此函数将MyClass
引用作为参数。这意味着整数文字 1 100
必须转换为MyClass
。 C ++实现可以自由地执行一个这样的隐藏的用户定义的转换。它就是在这种情况下做到的。因为您未在MyClass(int myFirstValue)
中初始化整数成员,所以会发生默认初始化 2 。对于int
变量,表示没有初始化和未确定值。然后尝试读取并将此未定义值分配给原始对象。这会导致未定义的行为,因此从现在开始,程序的行为未定义,非确定性。
您可以使用单词explicit
限制只能显式调用构造函数,并解决问题初始化整数成员:
MyClass( int myFirstValue) : myValue( myFirstValue)
{
//....
}
C ++标准版n3337 § 12.3转换
1)类对象的类型转换可以由构造函数指定 并通过转换功能。这些转换称为用户定义 转换并用于隐式类型转换(第4条),for 初始化(8.5),以及显式类型转换(5.4,5.2.9)。
2)用户定义的转换仅适用于它们的位置 明确的(10.2,12.3.2)。转换遵循访问控制规则 (第11条)。模糊度解决后应用访问控制 (3.4)。
3)[注:有关转换使用的讨论,请参阅13.3 函数调用以及下面的示例。 - 结束说明]
4)最多一个用户定义的转换(构造函数或转换) function)隐式应用于单个值。
1 C ++标准版n3337 § 2.14.2文字1)整数文字是一个没有句点或指数部分的数字序列。整数文字可能有 指定其基数的前缀和指定其类型的后缀。序列的词汇第一个数字 数字是最重要的。十进制整数文字(十进制)以0和0以外的数字开头 由一系列十进制数字组成。八进制整数文字(基数为8)以数字0和0开头 由一个八进制数字序列组成.22一个十六进制整数文字(基数为16)以0x或0X开头, 由一系列十六进制数字组成,包括十进制数字和字母a到f 和A到F,十进制值为十到十五。 [例子:12号可写12, 014或0XC。 - 结束例子]
2 C ++标准版n3337 § 8.5初始值设定项6)默认初始化类型为T的对象意味着: - 如果T是(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(并且 如果T没有可访问的默认构造函数,则初始化是不正确的); - 如果T是数组类型,则每个元素都是默认初始化的; - 否则,不执行初始化。 如果程序要求对const限定类型T的对象进行默认初始化,则T应为类 使用用户提供的默认构造函数键入。