浅谈初始化列表
浅谈初始化列表
chengzi在之前的成员函数一文中谈到过构造函数,在创建对象时,编译器会调用构造函数,为成员变量进行赋值。但这个操作
并不是初始化
,初始化只能有一次
,而在构造函数里面是可以进行多次赋值的。初始化的工作通常可以交由初始化列表来执行。
什么是初始化列表?
C++的初始化列表
是一种在创建对象时初始化成员变量
的特殊语法。它的存在可以显著的提高代码的可读性和性能。
在C++中,当我们创建一个对象时,我们需要为其成员变量赋值
。通常情况下,我们会在构造函数中对成员变量赋值。但是,当对象中有大量成员变量时,这种方法可能会让代码变得冗长。
C++的初始化列表提供了一种更简洁、更清晰的方法来初始化成员变量。它使用冒号分隔符
来定义一个初始化列表,并在其中列出成员变量及其初始值。
下面是一个类:
1 | class A{ |
在上述的代码里,使用了初始化列表来为a与b赋值而没有经过构造函数体内。这就是初始化列表的基础用法。
使用初始化列表有一些需要注意的地方:
- 成员变量在初始化列表里只可以有一次。
- 当类中包含
引用成员变量,const成员变量,自定义类型成员变量(该类没有默认构造函数时)
时,必须放在初始化列表里进行初始化。
初始化列表的使用
在需要注意的第二点中我们提到了一旦包含上面的三个成员,就要放入初始化列表中进行初始化。
1 | class A{ |
如果B类不存在默认构造函数,那么就需要在A的初始化列表中对b1进行一个显式的调用。例如:
1 | class B { |
因为在创建A对象时,编译器需要为其成员变量分配内存并初始化
,如果B没有默认构造函数,那么编译器不知道如何为b1分配内存
并初始化,从而产生编译错误。
并且请注意:成员变量在类中的声明次序
就是其在初始化列表中的初始化顺序,而与其在初始化列表的顺序是无关
的!
一个很经典的例子:
1 | class A{ |
虽然在初始化列表中的顺序是a1,a2,但真正的执行顺序是a2,a1,也就是a2的初始化是一个随机值(因为此时a1就是随机的),在a2初始化完成之后a1才会被a赋值。
为什么引用,const或者类变量必须在初始化列表中?
const,引用类型或者类的成员变量必须要放在初始化列表
里面,因为它们在创建对象时需要被初始化,而且只能在初始化时被赋值,不能在构造函数中再次被赋值。
1 | private: |
上面三个变量的特征就是在定义时就必须被初始化
!
在C++中,对象的创建分为两个步骤:分配内存和初始化
。在分配内存的过程中,编译器会为对象中的每一个成员变量分配内存空间;在初始化的过程中,编译器会调用构造函数来初始化每一个成员变量。对于const或者引用类型的成员变量,其值必须在初始化时被赋值,因此必须在构造函数的初始化列表中进行初始化
,否则会导致编译错误。
另外,const或者引用类型的成员变量在对象的整个生命周期中都不能被修改
,因此也不能在构造函数中再次被赋值。因此,将其放在初始化列表中进行初始化,可以确保它们的值只被赋值一次,并且在对象的整个生命周期中保持不变。