查看: 113|回复: 2

C++ 构造函数为什么要用 Initializer Lists?

[复制链接]

3

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2022-11-27 19:06:35 | 显示全部楼层 |阅读模式
先来看看语法
1. 普通构造 VS 初始化列表构造

// 普通传参构造
class Actor
{
public:
    Actor(const std::string& name, int weight)
    {
        m_Name = name;
        m_Weight = weight;
    }
private:
    std::string m_Name;
    int m_Weight;
};

// 初始化列表构造
class Actor
{
public:
    Actor(const std::string& name, int weight)
        : m_Name(name), m_Weight(weight)
    {
    }
private:
    std::string m_Name;
    int m_Weight;
};
目前看来没什么区别,就是写法不太一样,现在我们来考虑一下特殊情况
2. 特殊情况

0. 构造函数执行流程

在说初始化列表的优势之前,有必要先来看一下C++构造函数调用的全流程。当我们调用构造函数时,会有三个阶段依次进行,具体解释看这篇文章C++ 构造函数的执行过程(一) 无继承

  • 分配内存空间
  • 初始化成员变量
  • 进入构造函数体
可以看到成员变量的初始化是先与构造函数的函数体执行的,这就引出了一些问题
1. const成员变量

咱们现在想让 m_Name 变成 const,但是很明显 const 初始化之后就不能改变了



构造函数体内给 const 变量赋值报错

这时候就需要用到初始化列表了




可以看到,成功地初始化了类内 const 成员变量
2. 引用成员变量

众所周知,引用必须初始化,不能先声明,再赋值
int& weight; // 错误,引用必须初始化
const int& weight = 65; // 正确
// 注意加const但是我们就想在类内搞个引用,并且传参进来初始化。那这里又可以用初始化列表





成功构造

这里注意构造函数的形参得是引用,不要传字面值,传入变量的生命周期要比实例化出来的类要长,具体解释可以看这一篇文章
3. 其他实例成员变量

现在我们想给 Actor 成员变量中加一把武器,于算我们定义一个 Weapon 类,在调用默认构造和传参构造时打印一些字符串用来调试。




在打印字符串中我们可以看到 Weapon 的构造函数被调了两次,一次默认构造,一次有参构造,这就意味着我们创建了两个 Weapon 实例,出现这种情况的原因就是我们在上面所说到的构造函数的执行顺序,再看一遍:

  • 分配内存空间
  • 初始化成员变量
  • 进入构造函数体
注意第二步,类的成员变量的初始化其实在进入构造函数之前就已经完成了,因此,咱们首先是用 Weapon 的默认构造函数初始化了 m_Weapon ,待所有成员变量初始化完毕后进入构造函数体,在函数体内又调用了一次 Wepaon 的有参构造,使用拷贝赋值运算符,说白了就是 = ,将 m_Weapon 重新赋值。



构造函数体

在这里,咱们实例化出了两个对象,这显然是不合理的,如果 Weapon 内类有许多数据,那这样就会增加非常多的开销。
解决办法呢,依旧是 Initializer List


可以看到,只有一次构造函数的调用。
3. 总结

再看一眼流程

  • 分配内存空间
  • 初始化成员变量
  • 进入构造函数体
在普通构造中,我们只能对第 3 阶段进行操作,也就是构造函数体内部,2 阶段是编译器给咱们初始化并且分配一些默认值,初始化列表就是将第 2 阶段暴露出来让我们操作,让我们来决定初始化的值,而非默认值
普通构造

Cons :
不能传参构造 const 成员变量
不能传参构造引用成员变量
多次实例化类成员变量
Pros :
Nothing
初始化列表

Cons :
no ??
Pros :
解决上述所有问题
So, why don't you use this shit ?

(C++新手,如有错误,还请指正~)
回复

使用道具 举报

0

主题

1

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-11-27 19:07:21 | 显示全部楼层
int& weight = 65; // 正确,这个绑定65是错的吧,要const int &
回复

使用道具 举报

1

主题

10

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2022-11-27 19:08:06 | 显示全部楼层
是的,多谢指正[谢邀]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表