1 / 26

2008/4/22 課後輔導 實作拷貝建構子與多載運算子

2008/4/22 課後輔導 實作拷貝建構子與多載運算子. 課程內容. 本週實習程式講解 拷貝建構子 多載運算子 賦值運算子( = ) 串流插入運算子( << ). 實習程式講解. 本週實習程式. 請實作一個類別 CppString ,用以儲存字串並操作字串相關運算, private 成員資料中請以 char * 來實作此類別。 在類別中實作以下成員函數: 建構子、解構子與拷貝建構子 多載運算子「 operator== 」 多載運算子「 operator= 」 length() :回傳字串長度。 多載串流擷取運算子「 >> 」

price-bates
Download Presentation

2008/4/22 課後輔導 實作拷貝建構子與多載運算子

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 2008/4/22 課後輔導實作拷貝建構子與多載運算子

  2. 課程內容 • 本週實習程式講解 • 拷貝建構子 • 多載運算子 • 賦值運算子(=) • 串流插入運算子(<<)

  3. 實習程式講解

  4. 本週實習程式 • 請實作一個類別CppString,用以儲存字串並操作字串相關運算,private成員資料中請以char *來實作此類別。 • 在類別中實作以下成員函數: • 建構子、解構子與拷貝建構子 • 多載運算子「operator==」 • 多載運算子「operator=」 • length():回傳字串長度。 • 多載串流擷取運算子「>>」 • 多載串流插入運算子「<<」

  5. 練習一:建立類別 • 請建立類別設計的架構 • 成員變數: • 依題意,加入一個指向字元陣列的指標變數,另外,需要額外的變數以記住陣列的大小 • 成員函式 • 預設建構子 • 以輸入的字串作為初始值,欲設為空字串;例如: CppString(const char *s = “”); • 解構子 • 測試函式Output:用以列印成員變數,檢查資料是否正確 • 請撰寫簡單的main函式,編譯你的類別並測試物件的建立是否正確。 • 注意char*型態的字串處理需加入標頭檔<cstring>

  6. 拷貝建構子

  7. Shallow Copy • 如果類別沒有給予拷貝建構子或多載賦值運算子(=),其預設的物件拷貝是將其成員內容逐一的複製。 • 範例: 物件B class BigObj { char buf[100]; int i; }; void main() { BigObj A, B; A = B; } char buf[100] int i 物件A

  8. Shallow Copy • 如果當類別中有成員變數是指標變數的時候,考慮以下類別: class BigObj2 { public: BigObj2(int s=100) { capacity = (s > 0)? s : 100; buf = new char[capacity]; } ~BigObj2() { delete [] buf; } private: int capacity; char *buf; }; 在這個類別中有一個指標變數,指向一個字元的陣列;成員變數capacity用來記住目前陣列的大小。

  9. Shallow Copy • 在預設的情況下,兩個指標變數的拷貝僅僅拷貝了記憶體位址,非針對實體的資料進行拷貝。 物件B Shallow Copy int capacity char *buf 30000 預設的拷貝動作,是對成員變數逐一的複製 30000 38000 38000 30000 物件A

  10. Shallow Copy的問題 • 考慮以下程式碼將發生的情形: • func()接受一個物件做為參數,再將此物件回傳。 • main函式宣告兩個物件A與B,並將A傳入func後,以B物件來接受其回傳值。 BigObj2 func(BigObj2 X) { return X; } void main() { BigObj2 A, B; B = func(A); }

  11. Shallow Copy的問題 main() func() main() 暫存的物件T Copy Copy Copy A X B 物件T operator= int capacity char *buf 30000 暫存的物件在函式結束呼叫便會被清除 30000 ? Dangling Pointer 38000 38000 30000 Memory Leak 物件B

  12. 自訂拷貝建構子與多載賦值運算子 • 使用時機 • 當成員變數含有指標變數的時候,最好提供自訂以下函式: • 預設建構子 • 不管什麼時機,都盡量提供一個預設建構子 • 自訂的拷貝建構子 • 多載賦值運算子(operator=)

  13. 自訂拷貝建構子 • 呼叫時機: • 從一個既存物件A中建立一個新的物件,且此物件為A的複本。 • 函式原型: • 沒有回傳值 • 一定只有一個參數,例: const BigObj2 & • 一定是一個const的參考指向傳入的物件;代表該傳入的物件不可被修改。

  14. 自訂拷貝建構子 class BigObj2 //因篇幅有限故直接寫入類別中,實作時請將函式原型 { //與實作分開 public: … BigObj2(const BigObj2 &source) { capacity = source.capacity; buf = new char[capacity]; for (int i=0; i<capacity; i++) buf[i] = source.buf[i]; } private: … }; 直接複製capacity 根據capacity,再次new一個新的陣列 逐一複製陣列中的元素

  15. 練習二:加入拷貝建構子 • 請於類別中加入拷貝建構子 • 請撰寫簡單的main函式,編譯你的類別並測試物件的建立是否正確。 • 例: CppString A(“hello”); CppString B = A; B.Output();

  16. 多載賦值運算子

  17. 多載賦值運算子 • 呼叫時機: • 將一個既存物件B指定給另一個既存的物件A的時候 • 呼叫賦值運算子(operator=) BigObj A, B; A = B; //等同於呼叫A.operator=(B); • 與實作拷貝建構子的差別 • 因為賦值運算子是拷貝到一個「已經存在」的物件,表示原物件中已經有一些資料存在,故需增加一個程式碼來對舊有資料作清除,且需要判斷指定的物件是否就是自己本身。

  18. 多載賦值運算子 class BigObj2 { public: … BigObj2 &operator=(const BigObj2 &source) { if (this == &source) //判斷指定的物件是否就是自己本身 return *this; //例如: A = A; if (buf != NULL) //將自己所指向的記憶體釋回 delete [] buf; capacity = source.capacity; //以下同拷貝建構子的內容 buf = new char[capacity]; for (int i=0; i<capacity; i++) buf[i] = source.buf[i]; return *this; //將自己本身回傳 } private: … };

  19. 多載賦值運算子 • 介面說明;以類別BigObj為例: • 參數:const BigObj &source • 接受一個和自己同型態的物件參考,且指定const,代表傳入的物件不可修改。 • 注意傳入參考使得副函式具有更改到原物件的能力,加上const可保證傳入的物件不會被副函式任意更動。 • 通常賦值運算子會把自己(*this)回傳,回傳的型態是一個指向該物件的參考。這樣做的目的是為了實現「連鎖」的指定,例如: A = B = C; • 此行敘述等同於 A.operator=(B.operator=(C));

  20. 練習三:加入operator=() • 請於類別中多載賦值運算子 • 請撰寫簡單的main函式,編譯你的類別並測試物件的建立是否正確。 • 例: CppString A(“hello”); CppString B(“world”); B.Output(); B = A; B.Output();

  21. 多載串流插入運算子

  22. 多載串流插入運算子 • 例如: cout << classObject • 因為串流插入運算子的左邊是串流輸出物件,型態為ostream &,故不能把他以類別的成員函式的方法多載 • 因此必須以副函式的方式來多載。 • 同樣,在多載串流擷取運算子的時候也是一樣要用副函式的方式多載。

  23. 多載串流插入運算子 • 程式範例:以複數類別Complex為例 • 底層包含實部與虛部兩部分 • 我們希望利用>>運算子印出他的物件時,會自動印出以下這種形式: 3 + 5i

  24. 範例 class Complex { friend ostream &operator<< (ostream &out, Complex &P); public: … private: int real, imaginary; }; ostream &operator<<(ostream &out, Complex &P) { out << P.real << “+” << P.imaginary << “i”; return out; }

  25. 範例 • In main(): #include <iostream> using namespace std; int main() { Complex P, Q; … cout << P; cout << P << Q; return 0; } This statement is interpreted as: operator<<(cout, P); This statement is interpreted as: operator<< (operator<<(cout, P), Q);

  26. 練習四:多載串流插入運算子 • 請於類別中多載串流插入運算子 • 請撰寫簡單的main函式,編譯你的類別並測試物件的建立是否正確(把呼叫Output()的部分改用<<運算子的方式輸出)。 • 例: CppString A(“hello”); CppString B(“world”); cout << B << endl; B = A; cout << B << endl;

More Related