初始化列表

# 问题

下面三种说法:

说法一


struct Obj {
    int x;
    int& xx;
    Obj () {
        x = 10;
        xx = x;
    }
}

Obj obj; obj.xx ++;
std::cout << obj.x;
1
2
3
4
5
6
7
8
9
10
11

会输出 11

说法二


struct Obj {
    const int x;
    Obj () {
        x = 10;
    }
};
Obj obj;
std::cout << obj.x;
1
2
3
4
5
6
7
8

会输出 10

说法三


struct Obj {
    int x, y, z;
    Obj (int i) : 
            z(i), 
            y(z + 1), 
            x(y + 1) 
    {}
};
...
Obj obj(100);
std::cout << obj.x << " " << obj.y << " " << obj.z << "\n";
1
2
3
4
5
6
7
8
9
10
11

会输出 102 101 100

都有哪些是正确的

答案

全错了,不然我写它干啥
前两个编译错误,最后一个答案错误

下面来说说问题在哪

# 生命周期

赋值构造的生命周期是先构建变量,再在赋值部分初始化
比如说法二中的就是相当于

const int x;
x = 10;
1
2

这种肯定是有问题的,const 修饰的变量不可修改
以及第一个同理,引用变量应在构建的时候就指明绑定对象,后期不可修改

初始化列表是在成员变量构造时完成初始化

初始化列表就是在构造函数后面跟着变量+初始化,以逗号分割,如下:

struct Obj {
    const int x;
    int y;
    int &yy;

    Obj () :
            x(10),
            y(20),
            yy(y)
    {}
};

Obj obj;
obj.yy ++;
std::cout << obj.x << " " << obj.y << " " << obj.yy << std::endl;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

会输出 10 21 21 ,这里的 const 变量和引用变量都没有问题,输出也是正常的结果

# 构造顺序

这是第三个说法错误的指正,当然不可以理所应当地认为第三种构造就是

int z = i;
int y = z + 1;
int x = y + 1;
1
2
3

实际上,它内部的构造顺序为

extern int x, y, z;
int x = y + 1;
int y = z + 1;
int z = i;
1
2
3
4

成员变量的构造顺序与在类内的声明顺序相同
因此 xy 输出的是垃圾值 而我们可以推得,因为初始化列表是在构造之初完成的事情,所以初始化列表先于赋值部分,自己验证一下也很易得,这里不做说明

# 派生类构造

派生类可以直接调用父类的构造函数,来完成在父类内声明的成员变量的初始化

struct Base {
    int x, y;
    Base (int i):
            x(i * 2),
            y(i + 2)
    {}
};

struct Derived : public Base {
    int z;
    Derived (int j) :
            Base(j),
            z(j + 3)
    {}
};

Derived d(10);
std::cout << d.x << " " << d.y << " " << d.z << std::endl;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

输出 20 12 13

而我们根据上面的,以及”父类成员排在子类新建成员之前“这条性质可以知道,如果我们这样写

Derived (int j) :
        z(j + 3),
        Base(z)
{}
1
2
3
4

依然是不对的

Last Updated: 6/16/2023, 12:02:32 AM