理解對象的構造時發生的情況

當一個對象被創建時,會發生什麼情況呢?

例如:

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對象的拷貝構造函數安插到代碼中,以完成

對象的初始化工作,而構造函數的函數體內,什麼都不做,這樣,我們編制調用了一次構造函數,這便是效率的體現。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章