构造函数会破坏成员变量

时间:2015-02-01 18:06:25

标签: c++ variables constructor member

为什么在第二次调用构造函数时删除了初始化成员变量?

示例:

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

有没有办法保留初始化成员变量?

2 个答案:

答案 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应为类 使用用户提供的默认构造函数键入。