定義
與其他函數不同,構造函數除了有名字,參數列表和函數體之外,還可以有初始化列表,初始化列表以冒號開頭,後跟一系列以逗號分隔的初始化字段。
構造函數列表的初始化方式不是按照列表的的順序,而是按照變量聲明的順序同時初始化顯隱數據成員
從概念上來講,構造函數的執行可以分成兩個階段,初始化階段和計算階段,初始化階段先於計算階段.
初始化階段
所有類類型(class type)的成員都會在初始化階段初始化,即使該成員沒有出現在構造函數的初始化列表中.
計算階段
一般用於執行構造函數體內的賦值操作
初始化列表的使用場景
場景1
以下三種情況下必須使用初始化成員列表
情況一、需要初始化的數據成員是對象的情況(這裏包含了繼承情況下,通過顯示調用父類的構造函數對父類數據成員進行初始化);
情況二、需要初始化const修飾的類成員或初始化引用成員數據;
情況三、子類初始化父類的私有成員;在繼承裏面,只有初始化列表可以構造父類的private成員(通過顯示調用父類的構造函數)
場景2
效率問題:初始化類的成員有兩種方式,一是使用初始化列表,二是在構造函數體內進行賦值操作。
對於基本的類型,使用初始化列表效果不是非常明顯。
但是對於類來說使用初始化列表少了一次調用默認構造函數的過程,這對於數據密集型的類來說,是非常高效的。如果不用成員初始化類表,那麼類對自己的類成員分別進行的是一次隱式的默認構造函數的調用,和一次賦值操作符的調用,如果是類對象,這樣做效率就得不到保障
class A
{
public:
//A() {};
A(int a=10) {};//兩個都可以稱爲默認的構造函數
~A() {};
private:
int a;
};
class B
{
public:
B() {};//構造的時候調用一次隱形的構造函數,然後調用一次賦值操作符。
B(A &a ):a(a) {};//直接調用拷貝構造函數初始化a,省去了調用默認構造函數的過程。所以能使用初始化列表的時候儘量使用初始化列表.
~B() {};
private:
A a;
};
初始化列表的使用方法
#pragma once
#include <iostream>
using namespace std;
class ClassConst
{
public:
//方法一:通過數值對數據成員進行初始化
ClassConst():mAge(20), mKG(65), mID(0),addr(mAge)
{
mAge = 24;//先執行初始化列表在執行構造賦值。
//mKG = 66;const修飾的成員變量,構造函數也不能構造,需要使用初始化列表
}
//方法二:構造函數參數進行初始化
ClassConst(int age,int kg,int id) :mAge(age), mKG(kg), mID(id),addr(mAge) {}
void set() const
{
//mAge = 20;err 常函數不可以修改this->任何成員變量. mutable除外
mID = 2020623;
}
void show()
{
cout << "mAge=" << mAge << " mKG=" << mKG << " mID=" << mID << " addr=" << addr << endl;
}
private:
int mAge;//初始化列表與變量的聲明順序有關。
//如果數據成員爲const型,那麼該數據成員的值只能在初始化列表中被初始化或者定義直接初始化
const int mKG;//const修飾的變量,c++性質,編譯器會優化(相當於宏替換),如果沒有&和extern那麼不會有內存分配(被優化)
mutable int mID;
int& addr;
};