亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++動態數組類的封裝實例

2020-01-26 15:23:44
字體:
來源:轉載
供稿:網友

C++中的動態數組(Dynamic Array)是指動態分配的、可以根據需求動態增長占用內存的數組。為了實現一個動態數組類的封裝,我們需要考慮幾個問題:new/delete的使用、內存分配策略、類的四大函數(構造函數、拷貝構造函數、拷貝賦值運算符、析構函數)、運算符的重載。涉及到的知識點很多,對此本文只做簡單的介紹。

一、內存分配策略

當用new為一個動態數組申請一塊內存時,數組中的元素是連續存儲的,例如 vector和string。當向一個動態數組添加元素時,如果沒有空間容納新元素,不可能簡單地將新元素添加到內存中的其他位置――因為元素必須連續存儲。所以必須重新分配一塊更大的內存空間,將原來的元素從舊位置移動到新空間中,然后添加新元素,釋放舊的內存空間。如果我們每添加一個新元素,就執行一次這樣的內存分配和釋放操作,效率將會慢到不行。

為了避免上述的代價,必須減少內存重新分配的次數。所以我們采取的策略是:在不得不分配新的內存空間時,分配比新的空間需求更大的內存空間(通常為2倍)。這樣,在相當一段時間內,添加元素時就不用重新申請內存空間。注意,只有當迫不得已時才可以分配新的內存空間

二、類的四大函數

一個C++類一般至少有四大函數,即構造函數、拷貝構造函數、拷貝賦值運算符、析構函數。如果類未自己定義上述函數,C++編譯器將為其合成4個默認的版本。但是往往編譯器合成的并不是我們所期望的,為此我們有必要自己定義它們。

1.構造函數

類的構造函數(constructor)用來初始化類對象的非static數據成員,無論何時只要類的對象被創建,就會執行構造函數。

class Foo { public:   Foo(); // 構造函數   Foo(string &s);   // ... }; 

構造函數的名字和類名相同,沒有返回類型。類可以包含多個構造函數(重載),它們之間在參數數量或類型上需要有所區別。構造函數有一個初始化部分和一個函數體,成員的初始化是在函數體執行之前完成的。

2.拷貝構造函數

如果一個構造函數的第一個參數是自身類類型的引用,且任何額外參數都有默認值,則此構造函數是拷貝構造函數(copy constructor)。

class Foo { public:   Foo();   Foo(const Foo&); // 拷貝構造函數   // ... }; 

拷貝構造函數定義了如何用一個對象初始化另一個同類型的對象??截惓跏蓟ǔJ褂每截悩嬙旌瘮祦硗瓿伞?截惓跏蓟l生在下列情況中:

使用等號(=)初始化一個變量
將一個對象作為實參傳遞給一個非引用類型的形參
從一個返回類型為非引用類型的函數返回一個對象
用花括號列表初始化一個數組中的元素

3.拷貝賦值運算符

類的拷貝賦值運算符(copy-assignment operator)是一個名為operator=的函數。類似于其他任何函數,它也有一個返回類型和一個參數列表。

class Foo { public:   Foo();   Foo& operator=(const Foo&); // 賦值運算符   // ... }; 

拷貝賦值運算符定義了如何將一個對象賦值給另一個同類型的對象。賦值運算符是一個成員函數也是一個二元運算符,其左側運算對象就綁定到隱式的this指針,右側運算對象作為顯式參數傳遞。注意:為了與內置類型的賦值保持一致,賦值運算符通常返回一個指向其左側運算對象的引用。

4.析構函數

類的析構函數(destructor)用來釋放類對象使用的資源并銷毀類對象的非static數據成員,無論何時只要一個對象被銷毀,就會自動執行析構函數。

class Foo { public:   ~Foo(); // 析構函數   // ... }; 

析構函數的名字由波浪號(~)加類名構成,也沒有返回類型。由于析構函數不接受參數,因此它不能被重載。析構函數有一個函數體和一個析構部分,銷毀一個對象時,首先執行析構函數體,然后按初始化順序的逆序銷毀成員。

三、運算符的重載

重載的運算符是具有特殊名字的函數:它們的名字由關鍵字operator和其后要定義的運算符號共同組成。和其他函數一樣,重載的運算符也包含返回類型、參數列表、函數體,比如拷貝賦值運算符。

當我們定義重載的運算符時,必須首先決定是將其聲明為類的成員函數還是聲明為一個普通的非成員函數。有些運算符必須作為成員,而另一些運算符作為普通函數比作為成員更好:

賦值(=)、下標([ ])、調用(( ))和成員訪問箭頭(->)運算符必須是成員。
復合賦值運算符一般來說應該是成員,但并非必須,這一點與賦值運算符略有不同。
改變對象狀態的運算符或者與給定類型密切相關的運算符,如遞增、遞減、解引用運算符,通常應該是成員。
具有對稱性的運算符可能轉換任意一端的運算對象,例如算術、相等性、關系和位運算符等,因此它們通常應該是普通的非成員函數。
當然,除了賦值運算符之外,我們還需要為動態數組定義下標運算符operator []。下標運算符必須是成員函數。為了讓下標可以出現在賦值運算符的任意一端,下標運算符函數通常返回所訪問元素的引用。

四、動態數組類的封裝

下面給出了動態數組DArray類的接口:

class DArray { private:   double *m_Data; // 存放數組的動態內存指針   int m_Size;   // 數組的元素個數   int m_Max;    // 預留給動態數組的內存大小 private:   void Init();   // 初始化   void Free();   // 釋放動態內存   inline bool InvalidateIndex(int nIndex); // 判斷下標的合法性 public:   DArray();    // 默認構造函數   DArray(int nSize, double dValue = 0); // 構造函數,設置數組大小,默認值為dValue   DArray(const DArray& arr); // 拷貝構造函數   DArray& operator=(const DArray& arr); // 拷貝賦值運算符   ~DArray();    // 析構函數    void Print();  // 輸出顯式所有數組元素的值   int GetSize();  // 獲取數組的大?。ㄔ貍€數)   void SetSize(int nSize); // 重新設置數組的大小,若nSize小于原大小,截斷;否則,新元素置0   double GetAt(int nIndex); // 獲取指定位置元素   void SetAt(int nIndex,double dValue); // 重置指定元素的值   void PushBack(double dValue); // 追加一個新元素到數組末尾   void DeleteAt(int nIndex);   // 刪除指定位置地元素   void InsertAt(int nIndex, double dValue); // 插入一個新的元素到數組中   double operator[](int nIndex) const;   // 重載下標運算符[] }; 

下面是實現方法:

void DArray::Init() {   m_Size = 0;  // 默認情況下數組不包含元素   m_Max = 1;   m_Data = new double[m_Max]; }  void DArray::Free() {   delete [] m_Data; }  bool DArray::InvalidateIndex(int nIndex) {   if(nIndex>=0 && nIndex<m_Size)     return false;   else     return true; }  // 默認構造函數 DArray::DArray() {   Init(); }  // 構造函數 DArray::DArray(int nSize, double dValue) {   if(nSize == 0)     Init();   else   {     m_Size = nSize;     m_Max = nSize;     m_Data = new double[m_Max];     for(int i=0; i<nSize; ++i)       m_Data[i]=dValue;   } }  // 拷貝構造函數 DArray::DArray(const DArray& arr) {   m_Size = arr.m_Size; /*復制常規成員*/   m_Max = arr.m_Max;   m_Data = new double[m_Max];  /*復制指針指向的內容*/   memcpy(m_Data, arr.m_Data, m_Size*sizeof(double)); }  // 拷貝賦值運算符 DArray& DArray::operator=(const DArray& arr) {   if(this == &arr) /*自賦值*/     return *this;   m_Size = arr.m_Size;   m_Max = arr.m_Max;   /* 先將右側對象拷貝到臨時對象中,然后再銷毀左側對象*/    double *m_Temp = new double[m_Max];   memcpy(m_Temp, arr.m_Data, m_Size*sizeof(double));   delete [] m_Data;   m_Data = m_Temp;    return *this; }  // 析構函數 DArray::~DArray() {   Free(); }  // 打印數組 void DArray::Print() {   if(m_Size == 0)   {     cout << "Error: The empty array can't be Printed." << endl;     exit(0);   }   else   {     for(int i=0; i<m_Size; ++i)       cout << m_Data[i] << " ";     cout << endl;   } }  // 獲取數組大小 int DArray::GetSize() {   return m_Size; }  // 重置數組大小 void DArray::SetSize(int nSize) {   if(nSize < m_Size)  /*截斷*/   {     for(int i=nSize; i<m_Size; ++i)       m_Data[i] = 0;   }   if(m_Size<=nSize && nSize<=m_Max) /*新增元素置0*/   {     for(int i=m_Size; i<nSize; ++i)       m_Data[i] = 0;   }   if(nSize > m_Max)  /*需要重新分配空間*/   {     m_Max = nSize;     double *temp = new double[m_Max];     memcpy(temp, m_Data, m_Size*sizeof(double));     for(int i=m_Size; i<nSize; ++i)       temp[i] = 0;     delete [] m_Data;     m_Data = temp;   }   m_Size = nSize; /*設置數組大小*/ }  // 獲取指定位置元素 double DArray::GetAt(int nIndex) {   if(InvalidateIndex(nIndex))   {     cout << "Error: the index of GetAt is invalid!" << endl;     exit(0);   }   return m_Data[nIndex]; }  // 設置指定位置元素的值 void DArray::SetAt(int nIndex, double dValue) {   if(InvalidateIndex(nIndex))   {     cout << "Error: the index of SetAt is invalid!" << endl;     exit(0);   }   else   {     m_Data[nIndex] = dValue;   } }  // 追加一個新元素到數組末尾 void DArray::PushBack(double dValue) {   if(m_Size < m_Max)   {     m_Data[m_Size] = dValue;   }   else    {     m_Max = m_Max*2;     double* temp = new double[m_Max];     memcpy(temp, m_Data, m_Size*sizeof(double));     delete [] m_Data;     m_Data = temp;     m_Data[m_Size] = dValue;   }   ++m_Size; /*數組大小加1*/ }  // 從數組中刪除一個元素 void DArray::DeleteAt(int nIndex) {   if(InvalidateIndex(nIndex))   {     cout << "Error: the index of DeleteAt is invalid." << endl;     exit(0);   }   else   {       for(int i=nIndex; i<m_Size; ++i)       m_Data[i] = m_Data[i+1];     m_Data[m_Size-1] = 0;     --m_Size;   } }  // 插入一個新元素到指定位置 void DArray::InsertAt(int nIndex, double dValue) {   if(nIndex<0 || nIndex>m_Size)   {     cout << "Error: the index of InsertAt is invalid!" << endl;     exit(0);   }    if(m_Size < m_Max) /* 未滿,插入 */   {     for(int i=m_Size-1; i>=nIndex; --i)       m_Data[i+1] = m_Data[i];     m_Data[nIndex] = dValue;   }   else        /* 重新分配空間 */   {     m_Max = m_Max*2;     double* temp = new double[m_Max];     memcpy(temp, m_Data, m_Size*sizeof(double));     delete [] m_Data;     m_Data = temp;     for(int i=m_Size-1; i>=nIndex; --i)       m_Data[i+1] = m_Data[i];     m_Data[nIndex] = dValue;   }   ++m_Size; /* 數組大小加1 */ }  // 重載下標運算符[] double DArray::operator[](int nIndex) const {   if(nIndex<0 || nIndex>=m_Size)   {     cout << "Error: the index in [] is invalid!" << endl;     exit(0);   }   return m_Data[nIndex]; } 

經過簡單的測試,暫時還沒有發現Bug??赡軠y試并不全面,感興趣的讀者可以進一步測試并完善該程序。

附:String類的實現

C++ 的一個常見面試題是讓你實現一個 String 類,限于時間,不可能要求具備 std::string 的功能,但至少要求能正確管理資源。

如果你弄懂了上面DArray類的寫法,那么實現String類應該就不難了。因為面試官一般只是想考查你能不能正確地寫出構造函數、析構函數、拷貝構造函數、拷貝賦值運算符以及+、[ ]、<<、>>運算符重載等等。下面給出一個String類的接口,你可以自己試試手實現一下:

class String{    friend ostream& operator<< (ostream&,String&); //重載<<運算符    friend istream& operator>> (istream&,String&); //重載>>運算符  public:    String();  // 默認構造函數   String(const char* str);    // 帶參構造函數    String(const String& rhs);    // 拷貝構造函數    String& operator=(const String& rhs);  // 拷貝賦值運算符    String operator+(const String& rhs) const; //operator+    bool operator==(const String&);       //operator==   bool operator!=(const String&);       //operator!=     char& operator[](unsigned int);       //operator[]    size_t size() const;    const char* c_str() const;   ~String();  // 析構函數  private:    char *m_data; // 用于保存字符串  }; 

本文所述DArray類和String類的源碼及測試代碼可點擊此處本站下載。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
韩国三级电影久久久久久| 成人有码在线播放| 欧美日韩在线观看视频小说| 欧美一级淫片videoshd| 欧美日韩另类视频| 欧美性猛交xxxx乱大交蜜桃| 91精品国产色综合久久不卡98| 福利一区福利二区微拍刺激| 欧美另类老肥妇| 国内精品伊人久久| 欧美精品videossex性护士| 国产在线999| 青草青草久热精品视频在线观看| 97香蕉超级碰碰久久免费的优势| 日韩美女在线播放| 国产成人精品a视频一区www| 国产精品第3页| 久久艹在线视频| 精品国产一区久久久| 欧美性在线观看| 91精品视频网站| 欧美日韩国产精品一区| 欧美老女人在线视频| 精品久久香蕉国产线看观看亚洲| 欧美亚洲日本黄色| 欧美国产日韩一区二区三区| 欧美中文字幕精品| 欧美视频精品一区| 欧美极品少妇全裸体| 日本一欧美一欧美一亚洲视频| xxx欧美精品| 精品中文视频在线| 欧美日韩国产综合视频在线观看中文| 懂色av中文一区二区三区天美| 亚洲男人7777| 人人做人人澡人人爽欧美| 欧美成人激情在线| 国产欧美韩国高清| 国产精品视频一区二区高潮| 成人日韩在线电影| 精品亚洲va在线va天堂资源站| 欧美怡红院视频一区二区三区| 亚洲欧美国产制服动漫| 在线电影中文日韩| 欧美最猛性xxxxx(亚洲精品)| 欧美激情第1页| 欧美夫妻性生活xx| 国产日韩欧美视频在线| 欧美亚洲国产另类| 欧美亚洲一级片| yw.139尤物在线精品视频| 国产精品三级久久久久久电影| 中文字幕日韩精品有码视频| 成人激情视频小说免费下载| 亚洲美女av网站| 日韩久久精品成人| 亚洲欧美另类自拍| 国产不卡av在线免费观看| 亚洲人成电影网站色xx| 国产精品99久久久久久久久久久久| 欧美精品激情blacked18| 欧美亚洲激情在线| 久久全国免费视频| 午夜免费日韩视频| 国产精品久久久久国产a级| 久久久久久久999| 国产视频自拍一区| 国产日韩中文字幕| 成人自拍性视频| 中文日韩电影网站| 国产成人高清激情视频在线观看| 日韩高清av一区二区三区| 美女国内精品自产拍在线播放| 精品久久久久久国产91| 亚洲欧美国产视频| 日韩欧美一区视频| 久久久久久一区二区三区| 精品综合久久久久久97| 97av在线视频免费播放| 欧美在线激情视频| 亚洲欧洲成视频免费观看| 日韩精品日韩在线观看| 热99精品只有里视频精品| 日韩网站免费观看高清| 精品在线小视频| 欧美重口另类videos人妖| 久久艳片www.17c.com| 91精品国产九九九久久久亚洲| 55夜色66夜色国产精品视频| 韩剧1988免费观看全集| 国产精品青青在线观看爽香蕉| 国产精品黄页免费高清在线观看| 久久乐国产精品| 欧美丰满片xxx777| 国产精品久久久久久久久久久不卡| 欧美一性一乱一交一视频| 欧美在线中文字幕| 亚洲欧美在线看| 国产精品成人一区二区| 精品久久久久久电影| 国产午夜精品一区理论片飘花| 成人在线中文字幕| 国产精品日日摸夜夜添夜夜av| 国产精品永久免费观看| 欧美高清第一页| 亚洲a成v人在线观看| 亚洲第一精品夜夜躁人人爽| 欧美性xxxxx极品娇小| 亚洲男子天堂网| 粉嫩av一区二区三区免费野| 国产美女久久精品香蕉69| 亚洲午夜国产成人av电影男同| 欧美黄网免费在线观看| 亚洲美女免费精品视频在线观看| 国产精品久久久久9999| 欧美高清视频一区二区| 91久久精品久久国产性色也91| 国产精品高清免费在线观看| 97超视频免费观看| 国产噜噜噜噜噜久久久久久久久| 中文字幕一精品亚洲无线一区| 欧美久久精品一级黑人c片| 久久影视三级福利片| 日韩国产高清视频在线| 久久久久亚洲精品成人网小说| 欧美丰满少妇xxxxx| 精品色蜜蜜精品视频在线观看| 亚洲女人天堂成人av在线| 中文精品99久久国产香蕉| 欧美一级淫片播放口| 日韩av在线免费播放| 成人午夜小视频| 国产一区av在线| 亚州欧美日韩中文视频| 欧美视频在线观看 亚洲欧| 日韩精品久久久久| 中文字幕亚洲综合久久筱田步美| www国产精品视频| 亚洲精品免费在线视频| 国产视频精品在线| 亚洲精品电影在线| 91免费欧美精品| 国产精品91在线| 亚洲欧美制服另类日韩| 国产精品极品美女在线观看免费| 自拍视频国产精品| 欧美大尺度激情区在线播放| 欧美日韩在线免费| 亚洲白拍色综合图区| 国产成人精品a视频一区www| 久久精品国产亚洲7777| 中文字幕免费精品一区| 韩日欧美一区二区| 中文字幕在线国产精品| 久久精品国产v日韩v亚洲| 欧美黄色成人网| 日韩在线观看免费高清完整版| 久久久久久久久久亚洲| 久久亚洲春色中文字幕| 欧美放荡办公室videos4k| 一区二区亚洲欧洲国产日韩| 日韩欧美在线观看| 中文字幕视频一区二区在线有码| 欧美成人精品在线播放|