程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++中復制結構函數和重載賦值操作符總結

C++中復制結構函數和重載賦值操作符總結

編輯:關於C++

C++中復制結構函數和重載賦值操作符總結。本站提示廣大學習愛好者:(C++中復制結構函數和重載賦值操作符總結)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中復制結構函數和重載賦值操作符總結正文


媒介

這篇文章將對C++中復制結構函數和重載賦值操作符停止總結,包含以下內容:

1.復制結構函數和重載賦值操作符的界說;
2.復制結構函數和重載賦值操作符的挪用機會;
3.復制結構函數和重載賦值操作符的完成要點;
4.復制結構函數的一些細節。

復制結構函數和重載賦值操作符的界說

我們都曉得,在C++中樹立一個類,這個類中確定會包含結構函數、析構函數、復制結構函數和重載賦值操作;即便在你沒有明白界說的情形下,編譯器也會給你生成如許的四個函數。例如以下類:

class CTest
{
public:
     CTest();
     ~CTest();
 
     CTest(const CTest &);
     void operator=(const CTest &);
};

關於結構函數和析構函數不是明天總結的重點,明天的重點是復制結構函數和重載賦值操作。類的復制結構函數原型以下:

class_name(const class_name &src);

普通來講,假如我們沒有編寫復制結構函數,那末編譯器會主動地替每個類創立一個復制結構函數(也叫隱式復制結構函數);相反的,假如我們編寫了一個復制結構函數(顯式的復制結構函數),那末編譯器就不會創立它。

類的重載賦值操作符的原型以下:

void operator=(const class_name &);

重載賦值操作符是一個特殊的賦值運算符,平日是用來把已存在的對象指定給其它雷同類型的對象。它是一個特殊的成員函數,假如我們沒有界說這個成員函數,那末編譯器會主動地發生這個成員函數。編譯器發生的代碼是以單一成員停止對象復制的舉措。

總結了復制結構函數和重載賦值操作符的界說,只是讓我們懂得了它們,而沒有真實的深刻它們。接上去,再細心的總結一下它們的挪用機會。關於它們的挪用機會,我一向都沒有真實的明確過,所以這裡必定要好好的總結明確了。

復制結構函數和重載賦值操作符的挪用機會

對復制結構函數和重載賦值操作符的挪用老是產生在不經意間,它們不是經由我們顯式的去挪用就被履行了。關於這類隱式挪用的處所必定要多留意了,這也普通是有圈套的處所。如今我就用現實的例子來停止驗證;例子以下:

#include <iostream>
using namespace std;
 
class CTest
{
public:
     CTest(){}
     ~CTest(){}
 
     CTest(const CTest &test)
     {
          cout<<"copy constructor."<<endl;
     }
 
     void operator=(const CTest &test)
     {
          cout<<"operator="<<endl;
     }
 
     void Test(CTest test)
     {}
 
     CTest Test2()
     {
          CTest a;
          return a;
     }
 
     void Test3(CTest &test)
     {}
 
     CTest &Test4()
     {
          CTest *pA = new CTest;
          return *pA;
     }
};
 
int main()
{
     CTest obj;
 
     CTest obj1(obj); // 挪用復制結構函數
 
     obj1 = obj; // 挪用重載賦值操作符
 
     /* 傳參的進程中,要挪用一次復制結構函數
     * obj1入棧時會挪用復制結構函數創立一個暫時對象,與函數內的部分變量具有雷同的感化域
     */
     obj.Test(obj1);
 
     /* 函數前往值時,挪用復制結構函數;將前往值賦值給obj2時,挪用重載賦值操作符
     * 函數前往值時,也會結構一個暫時對象;挪用復制結構函數將前往值復制莅臨時對象上
     */
     CTest obj2;
     obj2 = obj.Test2();
 
     obj2.Test3(obj); // 參數是援用,沒有挪用復制結構函數
 
     CTest obj3;
     obj2.Test4(); // 前往值是援用,沒有挪用復制結構函數
 
     return 0;
}

在代碼中都參加了正文,這裡就不再做具體的解釋了。再次總結一下,假如對象在聲明的同時將另外一個已存在的對象賦給它,就會挪用復制結構函數;假如對象曾經存在了,然後再將另外一個已存在的對象賦給它,挪用的就是重載賦值運算符了。這條規矩很實用,願望年夜家能記住。

復制結構函數和重載賦值操作符的完成要點

在普通的情形下,編譯器給我們生成的默許的復制結構函數和重載賦值操作符就曾經夠用了;然則在一些特殊的時刻,須要我們手動去完成本身的復制結構函數。

我們都曉得,默許的復制結構函數和賦值運算符停止的都是”shallow copy”,只是簡略地復制字段,是以假如對象中含有靜態分派的內存,就須要我們本身重寫復制結構函數或許重載賦值運算符來完成”deep copy”,確保數據的完全性和平安性。這也就是年夜家經常說的深拷貝與淺拷貝的成績。上面我就供給一個比擬簡略的例子來講明一下:

#include <iostream>
using namespace std;
 
const int MAXSIZE = 260;
 
class CTest
{
public:
     CTest(wchar_t *pInitValue)
     {
          // Here, I malloc the memory
          pValue = new wchar_t[MAXSIZE];
          memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
          wcscpy_s(pValue, MAXSIZE, pInitValue);
     }
 
     ~CTest()
     {
          if (pValue)
          {
               delete[] pValue; //finalseabiscuit指出,感謝。2014.7.24
               pValue = NULL;
          }
     }
 
     CTest(const CTest &test)
     {
          // Malloc the new memory for the pValue
          pValue = new wchar_t[MAXSIZE];
          memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
          wcscpy_s(pValue, MAXSIZE, test.pValue);
     }
 
     CTest& operator=(const CTest &test)
     {
          // This is very important, please remember
          if (this == &test)
          {
               return *this;
          }
 
          // Please delete the memory, this maybe cause the memory leak
          if (pValue)
          {
               delete[] pValue; // 方恆剛指出的成績。異常感激 2014.3.15
          }
 
          // Malloc the new memory for the pValue
          pValue = new wchar_t[MAXSIZE];
          memset(pValue, 0, sizeof(wchar_t) * MAXSIZE);
          wcscpy_s(pValue, MAXSIZE, test.pValue);
          return *this;
     }
 
     void Print()
     {
          wcout<<pValue<<endl;
     }
 
private:
     wchar_t *pValue; // The pointer points the memory
};
 
int main()
{
     CTest obj(L"obj");
     obj.Print();
 
     CTest obj2(L"obj2");
     obj2.Print();
     obj2 = obj;
     obj2.Print();
 
     obj2 = obj2;
     obj2.Print();
 
     return 0;
}

特殊是在完成重載賦值結構函數時須要多多的留意,在代碼中我也添加了正文,年夜家可以賣力的浏覽一下代碼,然後就懂了,假如不懂的便可以留言問我;固然了,假如我哪裡懂得錯了,也願望年夜家能給我提出,我們配合提高。

復制結構函數的一些細節

1.以下哪些是復制結構函數

X::X(const X&);  
X::X(X);  
X::X(X&, int a=1);  
X::X(X&, int a=1, int b=2);

這些細節成績在這裡也說一說,我也是從他人的博客裡看到的,這裡本身也總結一下。關於一個類X, 假如一個結構函數的第一個參數是以下之一:

a) X&
b) const X&
c) volatile X&
d) const volatile X&

且沒有其他參數或其他參數都有默許值,那末這個函數是拷貝結構函數。

X::X(const X&);  //是拷貝結構函數  
X::X(X&, int=1); //是拷貝結構函數 
X::X(X&, int a=1, int b=2); //固然也是拷貝結構函數

2.類中可以存在跨越一個拷貝結構函數

class X
{
public:      
  X(const X&);      // const 的拷貝結構
  X(X&);            // 非const的拷貝結構
};

留意,假如一個類中只存在一個參數為 X& 的拷貝結構函數,那末就不克不及應用const X或volatile X的對象實施拷貝初始化。假如一個類中沒有界說拷貝結構函數,那末編譯器會主動發生一個默許的拷貝結構函數。這個默許的參數能夠為 X::X(const X&)或 X::X(X&),由編譯器依據高低文決議選擇哪個。在我的Visual Studio 2012中,當界說了多個復制結構函數今後,編譯器就會有warning,然則法式還能准確運轉。

總結

這篇文章對復制結構函數和重載賦值操作符停止了一些總結,重點是在復制結構函數與重載賦值操作符的挪用機會上;關於年夜家愛好總結的深拷貝與淺拷貝成績,我沒有效過量的文字停止解釋,我以為下面的代碼就足以解釋成績了。最初本身糾結已久的成績也就如許總結了,本身也完全的明確了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved