View
230
Download
4
Embed Size (px)
Citation preview
Chapter 12
Pointers and Dynamic Arrays
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2
Overview
• Pointers (12.1)• Dynamic Arrays (12.2)• Classes and Dynamic Arrays(12.3)
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 3
12.1Pointers ( 指標 )
• 指標的內容是變數的記憶體地址 • 記憶體地址可拿來當做變數的名稱
• 假如一個變數需要 3 個記憶體空間 ( 一般是以 byte 為單位 ), 則第 1 個記憶體空間的地址可當作該變數的名稱
• 當一個變數被用來當作 call-by-reference 的參數時 , 其實就是傳遞其記憶體地址
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 4
Pointers Tell Where To Find A Variable
• 指標就是用來告訴程式設計師某個變數在記憶體的地址
• 指標透過地址告訴程式設計師一個變數儲放在哪裡,所以說指標 指向 (“point” to) 一個變數
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 5
Declaring Pointers
• 指標變數必須宣告成含有 * • Example: 下例宣告指向一個 double 變數的指
標 :
double *p;
• ‘*’ 標示變數 p 是一個指標
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 6
Multiple Pointer Declarations
• 要在一個宣告中宣告多個指標,在每個指標前加上 ‘ *’• Example:
int *p1, *p2, v1, v2;
p1 and p2 指向 type int 的變數v1 and v2 是 type int 的變數
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 7
The address of Operator
• ‘&’ 運算子可用來得到某變數之記憶體地址,該結果可以給指向該變數資料型態的指標
• Example: p1 = &v1;
執行後, p1 指向 v1 v1 也可以被稱為 “ p1 指過去的變數 "
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 8
The Dereferencing Operator ( 提領:去除記憶體地址 )
• C++ 使用 ‘ *’ 運算子處理指標的另一個做法 • “p 指過去的變數” 在 C++ 中可以用 *p 表示
• ‘*’ 在這種狀況就是 提領 (dereferencing) 運算子• p 在這種狀況就是被提領了 (dereferenced)
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 9
這列執行後, v1 及 *p1 為相同變數
A Pointer Example
• v1 = 0;p1 = &v1;*p1 = 42;cout << v1 << endl;cout << *p1 << endl;
輸出 : 42 42
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 10
Pointer Assignment
• 指定運算子 ( = ) 可用在指標上• Example: 如果 p1 指向 v1 ,則
p2 = p1;
會使 *p2, *p1, 及 v1 都是同一變數的不同名稱
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 11
Display 12.1
Caution! Pointer Assignments
• 使用指標變數來進行指定 (assignment) 時要特別注意以下的不同
• p1= p3; // 改變 p1 指向之記憶體地址
• *p1 = *p3; // 改變 p1 指向之記憶體地址裡的值
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 12
The new Operator
• 使用指標時 , 即使沒有變數名稱也能改變該指標指向之記憶體裡的值• 下例新增一個指向整數 (int) 之無名變數的指標 :
p1 = new int;• 這個變數可以用 *p1 來處理 ( 存取其值 ) • *p1 可用於任何 integer 變數可以出現的地方
cin >> *p1; *p1 = *p1 + 7;
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 13
• 使用 new 運算子產生的變數叫做 動態變數 (dynamic variables)• 動態變數 在程式執行時才會被新增其記憶體空間 或 送
回給作業系統• Display 12.2 有 pointers and dynamic
variables 更多範例
Display 12.2 程式碼的解說在 Display 12.2
Display 12.3
Dynamic Variables
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 14
new and Class Types
• new 運算子用於類別 (class) 資料型態時會呼叫建構子 (constructor) 並配置記憶體給該物件
• 如果 MyType 是一個類別 class 資料型態 , 則
MyType *myPtr; // 產生指向一個 MyType 物件 // 的指標
myPtr = new MyType; // 呼叫 MyType 預設建構子 myPtr = new MyType (32.0, 17); // 呼叫 Mytype(double, int) 建構子
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 15
Basic Memory Management
• 記憶體中有一塊區域叫做自由儲存區 ( the freestore ) ,表示尚未配置給任何變數的記憶體區域,預留給在程式執行時所新增的動態變數• 新增的動態變數會使用 freestore 的記憶體• 如果 freestore 全部被用光了 , new 的呼叫就會失敗
• 不再需要的動態變數所佔用之記憶體可以回收至 freestore• 當程式不再使用一個變數時 , 該變數可被 delete 掉,
該變數所使用的記憶體就會回到 freestore
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 16
The delete Operator
• 當程式不再需要一個變數時 , 可以刪除 (delete) 他 以將記憶體回收至 freestore• Example:
delete p;
執行後, p 的值 ( 記憶體地址 ) 就是未定義 (undefined) ,且原來 p 所指向之記憶體就回收至 freestore
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 17
Dangling Pointers
• 使用 delete 於一指標變數 摧毀掉該變數所指向之動態變數
• 如有另一指標變數指向該動態變數 , 則該指標變數也會變成未定義 (undefined)
• 未定義之指標變數也叫做 dangling pointers ( 晃蕩指標 ) • 提領 (dereference) 一個 dangling pointer (*p) 通常會
使程式當掉
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 18
Automatic Variables
• 函式中宣告的變數所需的記憶體空間,通常在執行到該函式時會被新增,當程式離開該函式時,該函式所新增的記憶體空間會被回收• 這些可稱為自動變數, 因為他們的新增與回收是由執行
程式自動控制• 程式設計師必須運用 new 及 delete 手動控制指
標變數的新增及回收
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 19
Global Variables
• 在所有函式外面宣告之變數被稱為全域變數• 全域變數可在程式任何地方使用 ( 包括在函式內 )• 全域變數一般很少用
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 20
Type Definitions
• 一個名稱可以用來定義新的資料型態 , 該名稱之後就能用來宣告變數
• 關鍵字 typedef 就是用來定義新的資料型態的名稱• 語法 :
typedef Known_Type_Definition New_Type_Name;
• Known_Type_Definition 可以是任何資料型態
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 21
Defining Pointer Types
• 為避免使用指標時的錯誤 , 可以定義一個指標資料型態• Example: typedef int* IntPtr;
定義一個新的資料型態 , IntPtr, 給指向 int 變數的指標
• 之後 , 以下兩個宣告有相同意義 IntPtr p;
int *p;
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 22
Multiple Declarations Again
• 使用以下的新資料型態 IntPtr : typedef int* IntPtr;
• 可避免宣告兩指標變數時,犯了以下的宣告錯誤 : int *P1, P2; // 只有 P1 是指標變數, P2 不是
// 指標變數• 改用以下宣告 IntPtr P1, P2; // P1 and P2 都是指標變數
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 23
Pointer Reference Parameters
• 使用 typedef 的第 2 個好處是在函數的參數定義
• Example: void sample_function(IntPtr& pointer_var);
比下例清楚 void sample_function( int*& pointer_var);
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 24
Section 12.1 Conclusion
• Can you• Declare a pointer variable?• Assign a value to a pointer variable?• Use the new operator to create a new variable in the
freestore?• Write a definition for a type called NumberPtr to be
a type for pointers to dynamic variables of type int?• Use the NumberPtr type to declare a pointer variable
called my_point?
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 25
12.2Dynamic Arrays
• 動態陣列指陣列的大小必須於程式執行時才知道,無法於程式設計時就知道其大小。
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 26
Pointer Variables and Array Variables
• 陣列變數其實就是指向陣列第一個元素的指標變數• Example: int a[10];
typedef int* IntPtr; IntPtr p;
• a and p 為相同種類之變數
• 因為 a 是指向 a[0] 的指標變數 p = a;會使 p 與 a 指向相同的變數 ( a[0] )
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 27
Display 12.4
Pointer Variables As Array Variables
• 反方向來說,指標變數也可以當陣列變數來使用
• Example: p[0], p[1], …p[9] 都符合 C++ 的語法
• 變數 a 可以當作指標來使用,但是 a 的指標值 ( 即其記憶體地址 ) 不能被異動
• 以下不符合 C++ 的語法 : IntPtr p2;
… // p2 is assigned a value a = p2 // attempt to change a
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 28
Creating Dynamic Arrays
• 一般陣列的大小在程式設計師寫程式時就知道• 但假設程式設計師預估的值太大 ?
• 程式執行時浪費記憶體• 但假設程式設計師預估的值太小 ?
• 某些狀況下,程式可能無法執行
• 動態陣列就是要在程式執行時給程式剛好大小的陣列,不會太大,也不會太小
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 29
• 動態陣列是用 new 運算子產生
• Example: 下例產生一個含 10 個 double 元素之動態陣列 : typedef double* DoublePtr; DoublePtr d; d = new double[10];
• 這樣 d 就可以如一般陣列一樣使用 !
這可以是一個 integer 變數 !
Creating Dynamic Arrays
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 30
• ( 接上頁 ) d 這個指標變數指向 d[0]• 當程式不再需要這個陣列 , 這個陣列應該要回收至
freestore• Example: delete [ ] d;
• 中括號 [ ] 告訴 C++ 一個動態陣列要被回收刪除了,因此 C++ 會檢查此動態陣列的大小以了解應該要回收多少個元素
• 如果忘了加上 [ ] ,仍然為合法的 C++ 語法,但 C++ 會只回收陣列第 1 個元素
Display 12.5 (1)
Display 12.5 (2)
Dynamic Arrays (cont.)
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 31
Pointer Arithmetic
• 陣列所代表的記憶體地址可以執行加減運算• 以 double 動態陣列 , d, 為例 , 再提醒一次 d 指
向 d[0]• 運算式 d+1 為 d[1] 的地址, d+2 為 d[2] 的地址
• 注意加 指標 +1 會讓 指標加上該變數所需之記憶體的大小
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 32
Pointer Arithmetic Operations
• 指標的加加減減• ++ and - - 運算子可用於指標• 相同資料型態的兩個變數的指標可以拿來相減,可以得
到這兩個指標間的元素個數• 注意此兩個變數必須在同一陣列
• 下例顯示指標的加減 : for (int i = 0; i < array_size; i++) cout << *(d + i) << “ ” ; // 與 cout << d[i] << “ ” ; 同樣的意思
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 33
Multidimensional Dynamic Arrays
• 以下為產生一個 3x4 二維整數動態陣列 ( 相同方法可擴充至更高維動態陣列 ) 的注意事項• 視多維動態陣列 為 以陣列為基底 的陣列• ( 上層 )首先產生一個 “基底為整數指標” 之一維動態陣
列• 先定義 整數指標 的新資料型態 :
typedef int* IntArrayPtr;• 再定義其動態陣列 m:
IntArrayPtr *m = new IntArrayPtr[3];
• (底層 ) 其次,對 m 中的每一個指標 , 產生一個整數的動態陣列
• for (int i = 0; i<3; i++) m[i] = new int[4];
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 34
m IntArrayPtr's
int's
IntArrayPtr *
A Multidimensional Dynamic Array
• 上頁的二維動態陣列圖示如下 :
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 35
• 刪除多維動態陣列的方法 (先回收底層,再回收上層 )• 每一個呼叫 new 所產生的動態陣列都需要一個對應的
delete[ ] 呼叫• Example: 以下刪除上頁之二維動態陣列 :
for ( i = 0; i < 3; i++) delete [ ] m[i]; //先刪除底層的整數動態陣列 delete [ ] m; // 再刪除 IntArrayPtr 動態陣列
Display 12.6 (1) Display 12.6 (2)
DeletingMultidimensional Arrays
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 36
Section 12.2 Conclusion
• Can you• Write a definition for pointer variables that will be
used to point to dynamic arrays? The array elementsare of type char. Call the type CharArray.
• Write code to fill array "entry" with 10 numbers typed at the keyboard? int * entry; entry = new int[10];
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 37
12.3Classes and Dynamic Arrays
• 動態陣列的基礎資料型態可以是類別• 如 Watch *p;
X=10;
p = new Watch[x];
• 一個類別可以有 動態陣列的 成員變數• StringVar 就是一個範例 .
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 38
Program Example:A String Variable Class
• 我們將定義 StringVar 類別• StringVar 物件是用來代表字串• StringVar 物件使用字元動態陣列,其大小必須在執行
程式時才知道 • StringVar 類別與 11-2 的 string 類別功能相似
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 39
The StringVar Constructors
• StringVar 預設建構子 產生一個代表空字串的 StringVar 物件,此字串最大長度設為 100 (註:因為此字串可能變長,因此需預留空間 )
• StringVar 第 2 個建構子需要一個 int 的參數,來決定此空字串物件以後之最大長度值
• StringVar 第 3 個建構子需要一個 C-string的參數以…• 將該 C-string 的長度設為此字串之可能最大長度• 將該 C-string 複製到此字串之內部動態陣列變數上
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 40
Display 12.7 (1) Display 12.7 (2)
The StringVar Interface
• 除了建構子 , StringVar 的介面包括 :• 成員函式 :
• int length( );• void input_line(istream& ins);• friend ostream& operator << (ostream& outs,
const StringVar& the_string);
• Copy 建構子 … (晚點再討論 )• Destructor 解構子… (晚點再討論 )
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 41
Display 12.8
A StringVar Sample Program
• 使用 StringVar 在 Display 12.7 的介面我們可以寫一使用 StringVar 類別之程式• 此程式內的 conversation 函式可以:
• 產生 2 個 StringVar 物件 , your_name 及 our_name• your_name 的字串最長可達 max_name_size • our_name 初始值為 “ Borg” ,只能改變為不大於
4 個字元的字串
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 42
Display 12.9 (1)
Display 12.9 (2)
The StringVar Implementation
• StringVar 使用一個字元動態陣列來存放代表該字串的字元們• StringVar 建構子呼叫 new 為成員變數 value 產生動
態 字元陣列 • value 要用 ‘ \0’ (虛字元 ) 來中止字串 (請參考 11-1)• 此陣列之大小必須等到程式執行 new 時才會知道
• 建構子的參數 ( 不論是 預設建構子、一個整數參數之建構子、一個字串參數之建構子 中任一個 ) 會決定其大小
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 43
Dynamic Variables
• 只有呼叫 delete 運算子,動態變數 ( 及陣列 ) 才能回收• 即使一個區域指標變數在函式結束後自動回收 , 該指標
所指向的動態變數 ( 及陣列 ) 會留在程式中,除非呼叫 delete 將其回收
• 但是使用 SringVar 類別的程式設計師不可能知道 StringVar 是用了一動態陣列作為其私有成員變數,所以當程式不再需要一個 StringVar 物件時,不會也不能呼叫 delete 來回收動態陣列
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 44
Destructors
• 解構子是一個成員函數,當該類別的物件離開其有效範圍時 ( 如函式結束時、 for 迴圈結束時等等 ) ,解構子會被自動呼叫 • 解構子必須含有將建構子產生的動態陣列回收的程式碼• 一個類別僅需要一個不用任何參數的解構子• 解構子的宣告就是在預設建構子前加上 ~
• Example: ~StringVar( );
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 45
~StringVar
• StringVar 的解構子必須呼叫delete [ ] 來回收動態陣列的記憶體空間至自由儲存區 (the freestore)• Example: StringVar::~StringVar( )
{ delete [ ] value; }
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 46
Display 12.10 Display 12.11
Pointers as Call-by-Value Parameters
• 在函式呼叫時,將指標 (pointers) 作為 call-by-value 的參數會產生沒有預期到的結果• 記得參數 (parameters) 是函式的區域變數
• 在函式內改變參數 (parameter) 的值,不會造成引數 (argument 即呼叫函式的變數 ) 的值跟著改變
• 參數的值設為引數 (argument) 的值,當引數為指標時其值為一記憶體地址
• 因此參數及引數有相同之值 ( 即指標指向之記憶體之地址 )
• 如果參數用來改變其地址指向之記憶體內容 , 因為引數指向之記憶體即為參數指向之記憶體,因此引數指向之記憶體內容也改變了,如 Display 12.10, 12.11 所示
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 47
Copy Constructors
• 如果不想造成上頁的副作用 ( 即用指標變數做引數呼叫 call-by-value 的函式參數,可以改變此指標變數指向的變數的值 ) ,可用 複製 (copy) 建構子幫忙解決
• 複製建構子的參數之資料型態即為該類別• 此參數必須為 call-by-reference• 此參數通常是一個 constant 參數, ( 不改變引數物件
的內容 )• 此建構子產生一個完整且獨立的引數複製物件,讓引數
物件與該新生物件不會糾纏在一起
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 48
StringVar Copy Constructor
• StringVar 之複製建構子程式碼如下:• 產生一個新的動態陣列準備來放字串的字元• 將引數的字串 ( 即動態字元陣列 ) 複製到此物件剛產生
的動態字元陣列StringVar::StringVar(const StringVar& string_object)
: max_length(string_object.length() ){ value = new char[max_length+ 1]; strcpy(value, string_object.value);}
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 49
Calling a Copy Constructor
• 在宣告該類別的物件時,複製建構子與其他建構子的呼叫方式相同
• 複製建構子在以下狀況會被自動呼叫• 宣告時,當其引數為相同類別的物件• 當一個函式傳回一個該類別的值 ( 即物件 ) • 當一個 call-by-value 參數以該類別的物件作為引數呼
叫
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 50
The Need For a Copy Constructor
• 假設沒有複製建構子,下例顯示在引數呼叫時,會有什麼問題• void show_string(StringVar the_string)
{ …}
StringVar greeting("Hello");show_string(greeting);cout << greeting << endl;
• 當呼叫 show_string(greeting) 時 , greeting 被複製到參數 the_string
• the_string.value 被設為與 greeting.value 相同
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 51
greeting.value the_string.value
"Hello"
The Need For a Copy Constructor (cont.)
• 因為 greeting.value 及 the_string.value 都是指標 , 他們指向同一動態陣列
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 52
greeting.value the_string.value
Undefined
The Need For a Copy Constructor (cont.)
• 當 show_string 執行結束時 , the_string 的解構子會自動被執行 , 將 the_string.value 指向之動態陣列回收至自由儲存區 ( the freestore)
• 這時 greeting.value 指向的記憶體已經被回收至自由儲存區 ( the freestore)
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 53
The Need For a Copy Constructor (cont.)
• Greeting 這個 StringVar 物件有 2 個問題• 輸出 greeting.value 很可能會出現錯誤
• 有時 OK ,但不能靠運氣• 當離開 greeting 的有效範圍時 , 他的解構子會自動被呼
叫• 同一記憶體地址被解構子呼叫回收 2 次會造成系統錯誤
(system crashing error)
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 54
greeting.value the_string.value
"Hello" "Hello"
Copy Constructor Demonstration
• 當有了複製建構子,上面的問題就不會發生了• greeting.value 及 the_string.value 指向記憶體不同位
置
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 55
greeting.value the_string.value
"Hello" undefined
Copy Constructor Demonstration (cont.)
• 當 the_string 離開有效範圍 ( 即函式結束 ), StringVar 的解構子會被呼叫 , 將 the_string.value 回收至自由儲存區 (the freestore )
• greeting.value 仍然還在,可以被存取、被回收
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 56
When To Include a Copy Constructor
• 當一個類別的定義 ( 即實做 ) 需用到指標及 new 來動態配置記憶體 , 就需要複製建構子
• 當一個類別的定義沒有用到指標及 new 來動態配置記憶體 , 就不需要複製建構子
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 57
The Big Three
• 大三元包括• 複製建構子• 指定運算元 ( 下頁說明 )• 解構子
• 如果需要定義其中一個 , 三個就都需要定義
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 58
The Assignment Operator
• 給定以下宣告 : StringVar string(10), string2(20);這個程式碼 string1 = string2;是合法的語法
• 但是 , 因為 StringVar‘s 的成員變數 value 是一個指標 , 我們會將 string1.value 及 string2.value指向同一記憶體位置• 會使得前面討論複製建構子所提的問題又再重現
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 59
Overloading =
• 解決之道就是覆蓋 ( overload ) 指定運算子 ( = ) ,讓 StringVar 的指定不致產生問題• = 運算子是以成員函式 (member function) 來定義• Example: operator = declaration
void operator=(const StringVar& right_side);
• right_side 是 = 運算子右邊的引數
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 60
Definition of =
• StringVar 的 = 運算子的實做之一 :void StringVar::operator= (const StringVar& right_side){ int new_length = strlen(right_side.value); if (( new_length) > max_length) new_length = max_length;
for(int i = 0; i < new_length; i++) value[i] = right_side.value[i];
value[new_length] = '\0';}
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 61
= Details
• 這個 StringVar = 的版本的作法是• 比較 = 左右兩個 StringVar 物件的長度• 最多只改變左邊 StringVar 物件可允許的最大長度• 會將右邊物件的字串內容複製到左邊物件,而且彼此獨立不會互相影響
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 62
Problems with =
• 這個 = 的實做的問題• 通常我們不會去管右邊物件的字串內容大小,我們希望
要一個右邊物件的完整複製品 • 要完成以上要求 , 我們需要先回收左邊物件的動態陣列,然後配置夠大的動態陣列來容納右邊物件的字串內容
• 下頁顯示採用以上方法的一個嘗試,但這是一個有問題 (buggy) 的 = 運算子實做
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 63
Another Attempt at =
• void StringVar::operator= (const StringVar& right_side){ delete [ ] value; int new_length = strlen(right_side.value); max_length = new_length;
value = new char[max_length + 1];
for(int i = 0; i < new_length; i++) value[i] = right_side.value[i];
value[new_length] = '\0';}
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 64
A New Problem With =
• 上頁的 = 運算子實做的問題• 如果有人無聊到將 = 的左右兩邊設為相同物件的話
my_string = my_string;• 上頁的 = 運算子實做先回收左方物件的動態字元陣列 .• 由於左右兩邊為相同物件 , 右方的動態字元陣列也被回
收了,沒有辦法執行 strlen(right_side.value) ,也無法利用 right_side.value[i] 得到原來的各個字元
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 65
A Better = Operator
• void StringVar::operator = (const StringVar& right_side) { int new_length = strlen(right_side.value); if (new_length > max_length) // 只有需要更多空間 { // 時才回收
delete [ ] value; max_length = new_length; value = new char[max_length + 1]; }
for (int I = 0; i< new_length; i++) value[i] = right_side.value[i]; value[new_length] = '\0';}
Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 66
Section 12.3 Conclusion
• Can you
• Explain why an overloaded assignment operator is not needed when the only data consist of built-in types?
• Explain what a destructor does?
• Explain when a copy constructor is called?