當一個對象被創建時,會發生什麼情況呢?
例如:
template<typename T>
class boy{
public:
boy(const string &new_name, T *ptr){
name = newname;
adress = ptr;
}
......
private:
sting name;
T *adress;
}
對於上述這個類而言,當我們在某處執行 :
string *n_ptr = &n_adress;//一個之前被定義的string對象
boy<srting> *jerry = new boy("jerry", n_ptr);
此時會發生以下幾件事:
1.編譯器根據模板實例化一個boy<string>類,並生成相關的函數,這將在編譯期完成。
2.對於new boy("jerry", n_ptr);編譯器會根據字符串字面值生成一個臨時對象,然後下面的語句將變成:
string _temp("jerry");//這裏會調用string對象的構造函數。
boy<string> *jerry = new boy(_temp, n_ptr);
3.new 運算符會調用operator new標準庫函數爲對象分配空間,然後調用對象的構造函數。
4.在operator new 分配空間後,編譯器還要保證完成一件事情,那就是爲生成boy<string>對象而首先對該對象的各個數據成員
進行初始化。於是這裏相對應boy<string>類有兩個數據成員,一個時string類得對象,一個是T類(即string類)的指針。對string類
成員的初始化會調用string類得默認構造函數,於是,編譯器在這裏會生成調用string、類構造函數的代碼插入到代碼片段中。
5.執行boy<string>類得構造函數,即執行函數體,而在函數體中,又有兩個賦值語句:
name = new_name;
adress = ptr;
從第一個賦值語句可以看出,這裏又調用了以此string對象的operator =,於是,上面的那次默認構造函數的調用完全是多餘的。
而當我們將類改寫成:
template<typename T>
class boy{
public:
boy(const string &new_name, T *ptr):name(new_name),adress(ptr){
}
......
private:
sting name;
T *adress;
};
這時,我們所做的工作就簡單的多,成員初始化列表完成的功能只有一件事:告訴編譯器,我們將如此初始化我們的成員,
於是,當new操作符調用operator new 分配完對象的內存空間後,編譯器會把string對象的拷貝構造函數安插到代碼中,以完成
對象的初始化工作,而構造函數的函數體內,什麼都不做,這樣,我們編制調用了一次構造函數,這便是效率的體現。