说到构造函数,就必需要说到构造函数初始化列表。为何要说它呢,下面来给各位客官娓娓道来。(目前有许多博客对此处已经说的很好了,但是沙米在前篇给你们写了构造函数的理解和应用场景博客后,还想让你们再深刻的理解一下,故作此文章)ios
构造函数进化流程:函数
如今来详细聊聊:性能
一、使用格式this
构造函数的初始化列表以冒号开头,后面跟着一系列以逗号分隔的初始化字段。spa
class Teacher { public: Teacher(int x):i(x),j(x){}; //初始化列表 private: int i; int j; };
二、 构造函数执行的两个阶段.net
初始化阶段:全部类类型(class type)的成员都会在初始化阶段初始化,即便该成员没有出如今构造函数的初始化列表中。code
计算阶段:通常用于执行构造函数体内的赋值操做对象
使用常规构造函数赋值类对象:blog
#include <iostream> using namespace std; class Test_A { public: Test_A() { cout<<"构造函数Test_A()"<<endl; } Test_A(const Test_A& t1) { cout<<"拷贝构造函数Test_A()"<<endl; m_age = t1.m_age; } Test_A& operator = (const Test_A& t1) { cout<<"重载赋值运算符operator="<<endl; m_age = t1.m_age; return *this; } ~Test_A() { cout<<"析构函数~Test_A()"<<endl; } public: int m_age; }; class Test_B { public: Test_B(Test_A& t1) { m_b = t1; } public: Test_A m_b; }; /*此函数至关于一个舞台,展现此函数内对象的完整生命周期*/ void display() { Test_A t1; Test_B t2(t1); } int main() { display(); system("pause"); return 0; }
输出结果:生命周期
构造函数Test_A() 构造函数Test_A() 重载赋值运算符operator= 析构函数~Test_A() 析构函数~Test_A()
从输出结果中能够看出,在执行Test_B t2(t1)的过程:
先调用Test_A类的构造函数初始化成员对象 m_b (初始化阶段)
而后再调用Test_A类的重载赋值运算符函数,将t1赋值给m_b。 (计算阶段)
使用初始化列表(只需修改类Test_B中的构造函数):
class Test_B { public: Test_B(Test_A& t1):m_b(t1){}; //使用了构造函数的初始化列表 public: Test_A m_b; };
输出结果:
构造函数Test_A() 拷贝构造函数Test_A() 析构函数~Test_A() 析构函数~Test_A()
从输出结果中能够看出,执行Test_B t2(t1)的过程:
在初始化成员对象 m_b时,直接调用Test_A类的拷贝构造函数进行初始化。(初始化阶段)
无 (计算阶段)
三、为何须要——初始化列表
(1)性能的提升,对于内置类型,使用初始化列表和构造函数内赋值性能差异不是很大,可是对于类类型来讲,使用初始化列表,减小了一次计算阶段,若是是密集型类,效率将会更高。
(2) 成员的类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败,必须使用初始化列表
(3)const成员或引用类型的成员。由于const对象或引用类型只能初始化,不能对他们赋值,必须使用初始化列表
注意:类中成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的
四、本质(很重要)
在执行A类构造函数的初始化阶段,就将传入A类构造函数的参数值在A类的成员初始化时,进行了值得传递。
沙米才疏学浅,但愿你们多多给沙米提意见。,一块儿进步,提升。