拷貝構造函數和賦值運算符有哪些不同點和相同點

‘=’只有在賦值時,才調用賦值函數,當在聲明變量時,B b3=b1和B b4(b3)調用的函數是一樣的,均爲拷貝構造函數。

 
一、
拷貝構造,是一個的對象來初始化一邊內存區域,這邊內存區域就是你的新對象的內存區域賦值運算,對於一個已經被初始化的對象來進行operator=操作
class   A;     
 A  a;  
 A  b=a;   //拷貝構造函數調用  
 //或  
 A  b(a);   //拷貝構造函數調用  
 ///////////////////////////////////     
 A  a;  
 A  b;  
 b =a;   //賦值運算符調用  
你只需要記住,在C++語言裏,  
 String   s2(s1);  
 String   s3   =   s1;  
 只是語法形式的不同,意義是一樣的,都是定義加初始化,都調用拷貝構造函數。
 
二、
一般來說是在數據成員包含指針對象的時候,應付兩種不同的處理需求的 :
一種是複製指針對象,
一種是引用指針對象 copy大多數情況下是複製,=則是引用對象的    
即 深拷貝 和 淺拷貝
拷貝構造函數 是深拷貝
例子:  
  class   A  
  {  
          int   nLen;  
          char   *   pData;  
  }  
  顯然  
  A   a,   b;  
  a=b的時候,對於pData數據存在兩種需求  
  第一種copy  
      a.pData   =   new   char   [nLen];  
      memcpy(a.pData,   b.pData,   nLen);  
  另外一種(引用方式):  
      a.pData   =   b.pData  
   
  通過對比就可以看到,他們是不同的  
  往往把第一種用copy使用,第二種用=實現
 
三、
  和拷貝構造函數的實現不一樣    
  拷貝構造函數首先是一個構造函數,它調用的時候產生一個對象,是通過參數傳進來的那個對象來初始化,產生的對象。  
  operator=();是把一個對象賦值給一個原有的對象,所以如果原來的對象中有內存分配要先把內存釋放掉,而且還要檢查一下兩個對象是不是同一個對象,如果是的話就不做任何操作。
 
  一個例程
                 (自:
http://www.vckbase.com
以下討論中將用到的例子:
class CExample
{
public:
    CExample(){pBuffer=NULL; nSize=0;}
    ~CExample(){delete pBuffer;}
    void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
    char *pBuffer; //類的對象中包含指針,指向動態分配的內存資源
    int nSize;
};
這個類的主要特點是包含指向其他資源的指針。pBuffer指向堆中分配的一段內存空間。
 
一、拷貝構造函數
int main(int argc, char* argv[])
{
    CExample theObjone;
    theObjone.Init(40);
    
    //現在需要另一個對象,需要將他初始化稱對象一的狀態
    CExample theObjtwo=theObjone;
    ...
}
語句"CExample theObjtwo=theObjone;" 是 淺拷貝
如果類中定義了拷貝構造函數,這對象建立時,調用的將是拷貝構造函數,在拷貝構造函數中,可以根據傳入的變量,複製指針所指向的資源。
拷貝構造函數的格式爲:構造函數名(對象的引用)
提供了拷貝構造函數後的CExample類定義爲:
class CExample
{
public:
    CExample(){pBuffer=NULL; nSize=0;}
    ~CExample(){delete pBuffer;}
    CExample(const CExample&); //拷貝構造函數
    void Init(int n){ pBuffer=new char[n]; nSize=n;}
private:
    char *pBuffer; //類的對象中包含指針,指向動態分配的內存資源
    int nSize;
};
CExample::CExample(const CExample& RightSides) //拷貝構造函數的定義
{
    nSize=RightSides.nSize; //複製常規成員
    pBuffer=new char[nSize]; //複製指針指向的內容
    memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));
}

1 定義新對象,並用已有對象初始化新對象時,CExample(const CExample& RightSides)將被調用,而已有對象用別名RightSides傳給構造函數,以用來作複製。
原則上,應該爲所有包含動態分配成員的類都提供拷貝構造函數。
 
 
2  當對象直接作爲參數傳給函數時,函數將建立對象的臨時拷貝,這個拷貝過程也將調同拷貝構造函數。
例如
BOOL testfunc(CExample obj);
testfunc(theObjone); //對象直接作爲參數。
BOOL testfunc(CExample obj)
{
    //針對obj的操作實際上是針對複製後的臨時拷貝進行的
}

  3  還有一種情況,也是與臨時對象有關的
當函數中的局部對象被被返回給函數調者時,也將建立此局部對象的一個臨時拷貝,拷貝構造函數也將被調用
CTest func()
{
    CTest theTest;
    return theTest
}
二、賦值符的重載
下面的代碼與上例相似
int main(int argc, char* argv[])
{
    CExample theObjone;
    theObjone.Init(40);
    
    CExample theObjthree;
    theObjthree.Init(60);
    //現在需要一個對象賦值操作,被賦值對象的原內容被清除,並用右邊對象的內容填充。
    theObjthree=theObjone;
    return 0;
}

也用到了"="號,但與"一、"中的例子並不同,"一、"的例子中,"="在對象聲明語句中,表示初始化。更多時候,這種初始化也可用括號表示。
例如 CExample theObjone(theObjtwo);
而本例子中,"="表示賦值操作。將對象theObjone的內容複製到對象theObjthree;,這其中涉及到對象theObjthree原有內容的丟棄,新內容的複製。
"="的缺省操作只是將成員變量的值相應複製。舊的值被自然丟棄。
由於對象內包含指針,將造成不良後果:指針的值被丟棄了,但指針指向的內容並未釋放。指針的值被複制了,但指針所指內容並未複製。
因此,包含動態分配成員的類除提供拷貝構造函數外,還應該考慮重載"="賦值操作符號。
類定義變爲:
class CExample
{
    ...
    CExample(const CExample&); //拷貝構造函數
    CExample& operator = (const CExample&); //賦值符重載
    ...
};

//賦值操作符重載
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
}
三、拷貝構造函數使用賦值運算符重載的代碼
CExample::CExample(const CExample& RightSides)
{
    pBuffer=NULL;

    *this=RightSides     //調用重載後的"="

}


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/sinhua_ren/archive/2007/07/24/1704884.aspx

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