標籤:
建構函式
1、 什麼是建構函式
每個類都分別定義了它的對象被初始化的方式,類通過一個或幾個特殊的成員函數來控制其對象初始化的過程,這些函數即——建構函式。
建構函式的任務就是初始化對象的資料成員,無論何時只要類的對象被建立,就會執行建構函式。
2、 建構函式與其他函數的異同
相同之處:
①建構函式有一個(也可能是0個)參數列表和一個(也可能是0個)函數體。
②一個類可以包含多個建構函式,這和重載函數是一樣的
相異之處:
①建構函式的名字和類名相同,而其他函數則不行。
②建構函式沒有傳回型別。
③建構函式不能被聲明成const。
3、 預設建構函式
有時候我們沒有為類中的對象提供初始值,但是其對象肯定是要初始化的,實際上它們執行了預設初始化的過程。類通過一個特殊的建構函式來控制預設初始化過程,這個函數叫做——預設建構函式。預設夠造函數無須任何的實參。
如果我們的類沒有顯示的定義建構函式,那麼編譯器會為我們隱式的定義一個預設建構函式——合成的預設建構函式。
一般來說,對於任何的類都需要定義其自己的預設建構函式,因為有時候某些類不能依賴於合成預設建構函式,原因有三點:
①編譯器只有在發現類不包含任何建構函式時才會替我們產生一個預設建構函式。一旦定義了一些其他的建構函式,那麼除非我們再定義一個預設建構函式,否則將沒有預設建構函式。
②對於某些類來說,合成的預設建構函式可能執行的是錯誤的操作。比如在類中數組或者指標類型被預設初始化,那他們的值是未定義的。
③有時候編譯器不能為某些類合成預設的建構函式。比如,如果類中包含一個其他類的類型成員,且這個類型成員沒有預設建構函式,那麼編譯器將無法初始化該成員。
4、 定義建構函式
以下面的例子開始作介紹:
struct Sales_data{
Sales_data() = default; //採用預設建構函式
Sales_data(const string &s, unsigned int n,double p):
bookNo(s),units_sold(n),revenue(p*n){ }
//建構函式初始值列表
};
在上面的程式段中,
Sales_data() = default;
此建構函式不接受任何的形參,因此他是一個預設建構函式。在這裡定義這個建構函式的意義在於我們既需要其他形式的建構函式,也需要預設建構函式。這裡的這個函數完全等同於使用合成的預設建構函式。
在C++11新標準中,如果我們需要預設行為,那麼可以通過在參數列表後面寫上=default來要求編譯器產生建構函式。
再來看這句程式:
Sales_data(const string &s, unsigned int n,double p):
bookNo(s),units_sold(n),revenue(p*n) { }
這個定義中出現了新的表達方式和新的成分。我們將上面的語句分為三個部分:
1、“()”中的形參列表;
2、冒號“:”和花括弧“{}”之間的代碼。
3、“{}”中的內容。
對於1和3我們都好理解,對於2中新出現的表達方式,我們稱之為——建構函式初始值列表。這個初始值列表的功能是負責為新建立的對象的一個或幾個資料成員賦初始值。建構函式初始值是成員名字的一個列表,每個名字後面緊跟著用“()”括起來的成員初始值。不同的成員初始化通過逗號分隔開。
另外,我們注意到上面的兩個建構函式的函數體都是空的。這是因為這些建構函式的唯一目的就是為資料成員賦初值。
下面再看一段代碼:
Sales_data:Sales_data(std::istream &is)
{
read(is , *this); //read函數的作用是從is中讀取資料並儲存在
//this對象中
}
上面這個建構函式是在類的外部定義的。在外部定義與在類的內部定義,方法是一樣的。只是這個建構函式沒有建構函式初始值列表,或者說其初始值列表是空的。
C++學習筆記(十三):建構函式