1,關於賦值的疑問:
1,什么時候需要重載賦值操作符?
2,編譯器是否提供默認的賦值操作符?
2,關於賦值的疑問:
1,編譯器為每個類默認重載了賦值操作符;
1,意味着同類型的類對象可以相互賦值;
2,默認的賦值操作符僅完成淺拷貝;
3,當需要進行深拷貝時必須重載賦值操作符;
1,和拷貝構造函數相同;
4,賦值操作符與拷貝構造函數有相同的存在意義;
3,默認賦值操作符重載編程實驗:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Test 7 { 8 int* m_pointer; 9 public: 10 Test() 11 { 12 m_pointer = NULL; 13 } 14 Test(int i) 15 { 16 m_pointer = new int(i); 17 } 18 Test(const Test& obj) 19 { 20 m_pointer = new int(*obj.m_pointer); 21 } 22 Test& operator = (const Test& obj) 23 { 24 if( this != &obj ) // 避免自賦值; 25 { 26 delete m_pointer; 27 m_pointer = new int(*obj.m_pointer); 28 } 29 30 return *this; 31 } 32 void print() 33 { 34 cout << "m_pointer = " << hex << m_pointer << endl; 35 } 36 ~Test() 37 { 38 delete m_pointer; 39 } 40 }; 41 42 int main() 43 { 44 Test t1 = 1; 45 Test t2; 46 47 t2 = t1; // 默認賦值操作符的淺拷貝使得兩個對象內部指針指向同一片空間; 48 49 int i = 0; // C 語言中允許這樣,所以 C++ 中也必須允許; 50 i = i; 51 52 t2 = t2; // C++ 中也要允許自賦值,但是沒有意義; 53 54 t1.print(); 55 t2.print(); 56 57 return 0; 58 }
2,輸出結果:
m_pointer = 0x9387008
m_pointer = 0x9387018
3,賦值操作符重載注意事項:
1,賦值操作符返回值一定是引用,為了連續賦值;
2,參數類型一定是 const Type&;
3,不能自賦值;
4,返回當前對象;
4,關於賦值的疑問:
1,如果要進行深拷貝,拷貝構造函數和賦值操作符的實現都要自定義;
5,一般性原則:
1,重載賦值操作符,必然要實現深拷貝;
1,實現深拷貝和自定義賦值操作符及拷貝構造函數是充要條件;
6,數組類的優化編程實驗:
1,IntArray.h 文件:
1 #ifndef _INTARRAY_H_ 2 #define _INTARRAY_H_ 3 4 class IntArray 5 { 6 private: 7 int m_length; 8 int* m_pointer; 9 10 IntArray(int len); 11 IntArray(const IntArray& obj); 12 bool construct(); 13 public: 14 static IntArray* NewInstance(int length); 15 int length(); 16 bool get(int index, int& value); 17 bool set(int index ,int value); 18 int& operator [] (int index); 19 IntArray& operator = (const IntArray& obj); 20 IntArray& self(); 21 ~IntArray(); 22 };
2,首先寫出賦值操作符注意事項模板:
1 IntArray& IntArray::operator = (cosnt IntArray& obj) 2 { 3 if( this != &obj ) 4 { 5 6 } 7 8 return *this; 9 }
3,函數實現:
1 IntArray& IntArray::operator = (const IntArray& obj) 2 { 3 if( this != &obj ) 4 { 5 int* pointer = new int[obj.m_length]; 6 7 if( pointer ) 8 { 9 /* 復制參數對象中的元素 */ 10 for(int i=0; i<obj.m_length; i++) 11 { 12 pointer[i] = obj.m_pointer[i]; 13 } 14 15 /* 深拷貝 */ 16 m_length = obj.m_length; 17 delete[] m_pointer; 18 m_pointer = pointer; 19 } 20 } 21 22 return *this; 23 }
4,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 #include "IntArray.h" 4 5 using namespace std; 6 7 int main() 8 { 9 IntArray* a = IntArray::NewInstance(5); 10 IntArray* b = IntArray::NewInstance(10); 11 12 if( a && b ) 13 { 14 IntArray& array = a->self(); 15 IntArray& brray = b->self(); 16 17 cout << "array.length() = " << array.length() << endl; 18 cout << "brray.length() = " << brray.length() << endl; 19 20 array = brray; 21 22 cout << "array.length() = " << array.length() << endl; 23 cout << "brray.length() = " << brray.length() << endl; 24 } 25 26 delete a; 27 delete b; 28 29 return 0; 30 }
5,輸出結果:
1 array.length() = 5
2 brray.length() = 10
3 array.length() = 10
4 brray.length() = 10
6,使用二階構造后,拷貝構造函數是私有的,拷貝構造函數就沒有作用了,不允許拷貝構造,但是應該重載賦值操作符重載;
7,編譯器默認提供函數:
1,雖然類中什么都沒寫,但是編譯器會放四個函數實現進去;
8,下面的代碼輸出什么?為什么?
1,代碼示例:
1 string s = "12345"; 2 const char* p = s.c_str(); // 返回字符指針,代表 C 語言中的字符串; 3 4 cout << p << endl; 5 6 s.append("abced"); 7 8 cout << p << endl;
9,字符串問題 1 編程實驗:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 int main() 7 { 8 string s = "12345"; 9 const char* p = s.c_str(); // 只有這一行用了 C 方式; 10 11 cout << p << endl; 12 13 s.append("abced"); // p 成為了野指針 14 15 cout << p << endl; 16 17 return 0; 18 }
2,這段代碼混合了 C 和 C++ 的方式,出了意想不到的錯誤;
10,關於 string 的疑問 1:
1,string 對象內部維護了一個指向數據的 char* 指針,這個指針可能在程序 運行的過程中發生改變,我們盡量不要操作這個指針;
2,執行 s.append() 函數后,char* 指針指向了新的堆空間 0xFF445566,而將舊的堆空間 0xFF112233 釋放,此時 p 指針成了野指針;
3,學習 C++,並且用的是標准庫中的內容,所以現在采用的編程思想就應該是 C++ 編程思想,不要混合使用 C 和 C++ 思想;
11,下面的程序輸出什么?為什么?
1,代碼示例:
1 const char* p = "12345"; // p 可以用字符串對象代替; 2 string s = ""; // 混合了,該注意了; 3 4 s.reserve(10); 5 6 // 不要使用 C 語言中的方式操作 C++ 中的字符串 7 for(int i=0; i<5; i++) 8 { 9 s[i] = p[i]; 10 } 11 12 if( !s.empty() ) 13 { 14 cout << s << endl; 15 }
2,沒有輸出;
12,字符串問題 2 編程實驗:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 int main() 7 { 8 const char* p = "12345"; 9 string s = ""; 10 11 s.reserve(10); 12 13 // 不要使用 C 語言中的方式操作 C++ 中的字符串 14 for(int i=0; i<5; i++) 15 { 16 s[i] = p[i]; 17 } 18 19 if( !s.empty() ) // 打印不出; 20 { 21 cout << s << endl; 22 } 23 24 cout << s << endl; // 打印不出; 25 26 for(int i=0; i<5; i++) // 可以打印; 27 { 28 cout << s[i] << endl; 29 } 30 31 return 0; 32 }
2,更改程序為:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 int main() 7 { 8 const string p = "12345"; 9 string s = ""; 10 11 s = p; 12 13 cout << s << endl; 14 15 return 0; 16 }
3,C++ 工程中,盡量避免指針使用,字符串類出現就是為了替代字符指針;
13,關於 string 的疑問 2:
14,小結:
1,在需要進行深拷貝的時候必須重載賦值操作符;
1,也要重新定義拷貝構造函數;
2,賦值操作符和拷貝構造函數有同等重要的意義;
3,string 類通過一個數據空間保存字符串數據;
4,string 類通過一個成員變量保存當前字符串的長度;
5,C++ 開發時盡量避開 C 語言中慣用的編程思想;
1,字符串類得到的是字符串對象,直接用成員函數操作這個對象就可以,不需要用 C 語言中的 for 循環之類的;