0x01 介绍
C++类中有两种方式可以用来初始化成员变量,一种最常见的是在构造函数内部直接对成员函数赋值:
1 2 3 4 5 6 7 |
class CTest{ int m_a, m_b; CTest(int a, int b){ m_a = a; m_b = b; } } |
另外一种方式就是通过构造函数的初始值列表来完成初始化:
1 2 3 4 |
class CTest{ int m_a, m_b; CTest(int a, int b) : m_a(a), m_b(b){} } |
这种在构造函数后加一个冒号然后初始化的方式叫做构造函数初始值列表,它更优于第一种初始化方式。
0x02 初始值列表的必要性
在以下情况下,必需使用初始值列表方式来初始化:
- 类成员包含const对象时。
- 在类A没有提供默认构造函数且被类B包含或者继承时,类B必需使用默认初始化方式初始化A。
对于第一个条件比较好理解,因为const本身在初始化后是无法再赋值的,所以必须使用初始化列表来对其初始化。
对于第二种情况,因为根据构造函数的执行顺序,在构造类B时必须先构造类A的构造函数,但类A并没有提供默认的构造函数,此时导致编译器找不到合适的构造函数,所以对象构造失败。因此这里必须在初始值列表中初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#pragma once #include <iostream> class CAnimal { public: CAnimal(int weight) :m_weight(weight) { } int m_weight; }; class CDog { public: CAnimal m_a; const int m_b; CDog(int a, int b) : m_b(b), m_a(a){ } }; |
0x02 初始值列表的效率
使用普通方式初始化时编译器会先执行一次对象的默认构造函数,然后才会对其赋值,初始化时执行了两个步骤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> class CAnimal { public: CAnimal() { std::cout << "default" << std::endl; } // 添加默认初始化函数 CAnimal(int weight) :m_weight(weight) { } int m_weight; }; class CDog : public CAnimal { public: CDog(int weight) { m_weight = weight; } // 初始值列表,和上面的构造函数不可共存 CDog(int weight): CAnimal(weight) { } }; |
执行CDog构造函数时会先执行CAnimal的默认构造函数,输出defualt
然后后才会执行m_weight = weight
。但是对于初始值列表方式来说并不会执行两步,直接通过相应的构造函数初始化就完成了,相对来说简化了一个过程,效率肯定也会高一些。
0x03 初始化顺序
使用初始值列表初始化时,初始化的顺序是根据成员变量定义的顺序来的,并不是初始值列表的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class CAnimal { public: CAnimal(int weight) :m_weight(weight) { std::cout << weight << std::endl; } int m_weight; }; class CDog { public: CAnimal m_a, m_b; CDog(int a, int b) : m_b(b), m_a(a){ } }; |
实例一个对象CDog d(1, 2)
,结果会输出:
1 2 |
1 2 |
并不是根据初始值列表先用2初始化m_b,可见初始顺序是根据定义顺序来的。
评论