c++中構造函數調用另一構造函數的問題,如何避免生成臨時對象

轉自: http://blog.chinaunix.net/uid-26611383-id-3549733.html

題目如下:問下列代碼的打印結果爲0嗎?

#include <stdlib.h>

#include <iostream>

using namespace std;

struct CLS

{

    int m_i;

    CLS( int i ) : m_i(i){}

    CLS()

    {

        CLS(0);

    }

};

int main()

{

    CLS obj;

    cout << obj.m_i << endl;

    system("PAUSE");

    return 0;

}

我當時是這樣想的,構造函數就是爲對象分配內存的過程,其主要目的就是爲了對私有變量進行初始化,所以我就想一個對象不能調用
兩次構造函數,即使這兩種構造函數是重載過的,像題目中的

  CLS()

    {

        CLS(0);

    }
因爲不太確定,回來查了一下,原來我之前的理解雖然沾了點邊,但是還是沒有想到點子上去。
首先在對象沒有動態資源的時候,對象的內存分配在構造函數之前,此時構造函數的主要任務就是初始化對象的private成員,內存分配在構造函數執行之前,所以構造函數裏調用另一種形式的構造函數(帶參數的構造函數),其實編譯器又生成了一個臨時對象,這個臨時對象的
private成員通過其參數得到初始化,但是原來的對象的數據成員並沒有初始化,是個隨機值。看了下面的測試代碼,你就會明白一切

// 構造函數調用構造函數的問題.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
using namespace std;


class Widget
{
public:
Widget(int n)
{
m_idata = n;
cout<<"有參數的構造函數中的this:"<<this<<endl;
}

Widget()
{

cout<<"無參數的構造函數中的this:"<<this<<endl;
Widget(8888);
}


void print() const
{
cout<<"m_idata is:"<<m_idata<<endl;
}

private:
int m_idata;
};


int _tmain(int argc, _TCHAR* argv[])
{
Widget a;
a.print();
system("pause");
return 0;
}



很明顯在兩個構造函數中分別是兩個對象,而且原對象的private成員是個隨機值,所以我們要儘量避免在構造函數中調用另一形式的構造函數,那麼構造函數調用自身就可以了嗎?當然不行,這樣會陷入無窮遞歸,有興趣的可以實驗一下

如果實在避免不了構造函數調用另一形勢的構造函數時怎麼辦?網上查了下,可以用下面的方法解決,new (this)CLS(8888),
這種方式是在原來的對象上調用另一形勢的構造函數,不會生成新的臨時對象。
下面是演示代碼:
// 構造函數調用構造函數的問題.cpp : 定義控制檯應用程序的入口點。
//


#include "stdafx.h"
#include <iostream>
using namespace std;


class Widget
{
public:
Widget(int n)
{
m_idata = n;
cout<<"有參數的構造函數中的this:"<<this<<endl;
}

Widget()
{

cout<<"無參數的構造函數中的this:"<<this<<endl;
new (this)Widget(8888);
}


void print() const
{
cout<<"m_idata is:"<<m_idata<<endl;
}
private:
int m_idata;
};


int _tmain(int argc, _TCHAR* argv[])
{
Widget a;
a.print();
system("pause");
return 0;
}

程序輸出:

這時就沒有哪個臨時對象了,而且private數據成員已被初始化

總結:

     不帶參數的構造函數的實現裏去調用帶參數的構造函數時,並沒有完成對象內部的函數調用,而是優先選擇了通過帶參數構造函數又構造出了一個新的臨時對象,所以儘量避免在構造函數中調用構造函數,不管是構造函數自身還是重載過的構造函數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章