【題目】C++拷貝構造函數與C++臨時對象

一、拷貝構造函數

       1、拷貝構造函數定義

                    

class A { private: int _a;

public: A(){}; A(const A&); //定義拷貝構造函數,一定要有一個實現 };

A::A(const A& Aa) {  cout<<"拷貝構造"<<endl; }

     2、調用拷貝構造函數的時機 

//E1、聲明語句中,一個對象初始化另一個對象,前提是類必須存在拷貝構造函數
A obj1;
A obj2 = obj1;
//E2、對象作爲參數
void get(A obj) {}             //調用這個函數的時候,先會調用拷貝構造函數
//E3、函數返回一個對象
A get(){ A obj ; return obj;}  //

二、C++淺拷貝和深拷貝【7】

       1、淺拷貝

class A
{
private:
	int _a;
public:
	A(){};
	A(const A&);
	void setData(int a1){	_a = a1;  }
	void Output(){	cout<<"A::a = "<<_a<<endl;  }
};
A::A(const A& Aa)              //如果是淺拷貝,則,在這裏直接將一個對象的值賦值給另外一個對象
{
	 _a = Aa._a;
	cout<<"拷貝構造"<<endl;
}
int main(int argc, char* argv[]) 
{
	A a;
	a.setData(10);
	A b = a;
	b.Output();
}

       2、深拷貝           

CExample::CExample(const CExample& RightSides)
{
     pBuffer=NULL;
     *this=RightSides     //調用重載後的"="
}
//賦值操作符重載
CExample & CExample::operator = (const CExample& RightSides)
{
     nSize=RightSides.nSize; //複製常規成員
    char *temp=new char[nSize]; //複製指針指向的內容 
     memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));
    delete []pBuffer; //刪除原指針指向內容   (將刪除操作放在後面,避免X=X特殊情況下,內容的丟失)
     pBuffer=temp;   //建立新指向
    return *this
}

【點評】深拷貝,會將對象指針指向的動態內存中的值,拷貝到另外一個對象中,以防止內存泄露。另外,拷貝是將一個有值的對象賦值給空值的對象,而"賦值"操作符是將原來有值的對象中的值覆蓋,調用的是"=重載函數"。

三、拷貝構造函數調用時機

        1、對象作爲參數,調用構造函數

//淺拷貝中的例子加入如下代碼
bool SetA(A a)
{	
     return true;
}
//void main()
 SetA(a);
//彙編代碼
53:       A b = a;
004012CA   lea         eax,[ebp-4]    //a的指針
004012CD   push        eax
004012CE   lea         ecx,[ebp-8]    //b的指針
004012D1   call        @ILT+60(A::A) (00401041)
54:       b.Output();
004012D6   lea         ecx,[ebp-8]
004012D9   call        @ILT+15(A::Output) (00401014)
55:       SetA(a);
004012DE   push        ecx     
004012DF   mov         ecx,esp                    //當前棧已經開闢了臨時對象空間,相當於b的指針
004012E1   lea         edx,[ebp-4]
004012E4   push        edx            //a的指針
004012E5   call        @ILT+60(A::A) (00401041)
004012EA   call        @ILT+10(SetA) (0040100f)   //已經拷貝了到了ecx,所以就直接調用SetA(),此時esp就是臨時對象的指針
004012EF   add         esp,4                      //esp+4 還是指向臨時對象
2、返回一個對象             
CExample GetExpFun()
{
       return g_objExp;
}
    objExp2 = GetExpFunc();                
004013E4   lea         ecx,[ebp-40h]           //返回的臨時對象空間是進入main函數的時候,提前分配好的。
004013E7   push        ecx                     //先將對象壓棧       
004013E8   call        @ILT+25(GetExpFun)      //調用函數

 【點評】 返回對象時,也是在當前棧分配了臨時空間,會調用在函數中,調用拷貝構造函數,來賦值給臨時空間。相當於一箇中轉戰,先拷貝構造函數賦值給臨時空間,再用它。

參考:1、C++拷貝構造函數(深拷貝、淺拷貝)

2、C++拷貝構造函數和賦值操作

3、02類與對象(5)-拷貝構造

4、拷貝構造函數

5、C++臨時對象的學習筆記

6、拷貝構造函數的調用

7、拷貝構造函數與賦值運算符重載

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