13.7 - 非静态成员初始化

当编写具有多个构造函数(即大多数构造函数)的类时,在每个构造函数中都为所有成员指定默认值会产生冗余代码,而且如果更新成员的默认值,则需要修改所有的构造函数。

可以直接给普通的类成员变量(那些不使用static关键字的变量)一个默认初始化值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

class Rectangle
{
private:
    double m_length{ 1.0 }; // m_length 具有默认值 1.0
    double m_width{ 1.0 }; // m_width 具有默认值 1.0

public:
    void print()
    {
        std::cout << "length: " << m_length << ", width: " << m_width << '\n';
    }
};

int main()
{
    Rectangle x{}; // x.m_length = 1.0, x.m_width = 1.0
    x.print();

    return 0;
}

程序输出结果:

1
length: 1.0, width: 1.0

非静态成员初始化(也称为类内成员初始化)为成员变量提供默认值,如果构造函数不为成员本身提供初始化值(通过成员初始化列表),则构造函数将使用这些默认值。

不过,决定对象创建的仍然是构造函数。考虑下面的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

class Rectangle
{
private:
    double m_length{ 1.0 };
    double m_width{ 1.0 };

public:

    // 注意:没有默认构造函数

    Rectangle(double length, double width)
        : m_length{ length },
          m_width{ width }
    {
        // m_length 和 m_width 会被构造函数初始化(不会使用它们的默认值)
    }

    void print()
    {
        std::cout << "length: " << m_length << ", width: " << m_width << '\n';
    }

};

int main()
{
    Rectangle x{}; // 无法编译,因为不存在默认构造函数,即使成员具有默认值

    return 0;
}

尽管我们为所有成员提供了默认值,但由于没有提供默认构造函数,因此无法创建不带参数的 Rectangle 对象。

如果提供了默认初始化值,且构造函数通过成员初始化列表初始化成员,则优先使用成员初始化列表。下面的例子说明了这一点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

class Rectangle
{
private:
    double m_length{ 1.0 };
    double m_width{ 1.0 };

public:

    Rectangle(double length, double width)
        : m_length{ length },
          m_width{ width }
    {
        // m_length 和 m_width 会被构造函数初始化(不会使用它们的默认值)
    }

    Rectangle(double length)
        : m_length{ length }
    {
        // m_length 被构造函数初始化
        // m_width 则使用默认值 1.0
    }

    void print()
    {
        std::cout << "length: " << m_length << ", width: " << m_width << '\n';
    }

};

int main()
{
    Rectangle x{ 2.0, 3.0 };
    x.print();

    Rectangle y{ 4.0 };
    y.print();

    return 0;
}
1
2
length: 2.0, width: 3.0
length: 4.0, width: 1.0

注意,使用非静态成员初始化来初始化成员需要使用等号或大括号(统一)初始化式——圆括号初始化形式在这里不起作用:

1
2
3
4
5
6
class A
{
    int m_a = 1;  // ok (拷贝初始化)
    int m_b{ 2 }; // ok (大括号初始化)
    int m_c(3);   // 无效 (圆括号初始化)
};

COPY

法则

推荐使用非静态成员初始化来为成员变量提供默认值。