第36课 - 经典问题解析三

1、关于赋值的疑问

            什么时候需要重载赋值操作符?

            编译器是否提供默认的赋值操作?

 

            编译器为每个类默认重载了赋值操作符 

            默认的赋值操作符仅完成浅拷贝 

            当需要进行深拷贝时必须重载赋值操作符 

            赋值操作符与拷贝构造函数有相同的存在意义


2、编程实验

默认赋值操作符重载     36-1.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.         ifthis != &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.     t1.print();  
  50.     t2.print();  
  51.       
  52.     return 0;  
  53. }  


                        第36课 - 经典问题解析三

                    当初始化赋值时,即:Test t2 = t1 时调用的是默认拷贝构造


        问题分析

第36课 - 经典问题解析三


         —般性原则 

                重载赋值操作符,必然需要实现深拷贝!


3、编程实验

数组类的优化     IntArray.cpp

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. };  
  23.   
  24. #endif  


IntArray.cpp

  1. #include "IntArray.h"  
  2.   
  3. IntArray::IntArray(int len)  
  4. {  
  5.     m_length = len;  
  6. }  
  7.   
  8. bool IntArray::construct()  
  9. {  
  10.     bool ret = true;  
  11.       
  12.     m_pointer = new int[m_length];  
  13.       
  14.     if( m_pointer )  
  15.     {  
  16.         for(int i=0; i<m_length; i++)  
  17.         {  
  18.             m_pointer[i] = 0;  
  19.         }  
  20.     }  
  21.     else  
  22.     {  
  23.         ret = false;  
  24.     }  
  25.       
  26.     return ret;  
  27. }  
  28.   
  29. IntArray* IntArray::NewInstance(int length)   
  30. {  
  31.     IntArray* ret = new IntArray(length);  
  32.       
  33.     if( !(ret && ret->construct()) )   
  34.     {  
  35.         delete ret;  
  36.         ret = 0;  
  37.     }  
  38.           
  39.     return ret;  
  40. }  
  41.   
  42. int IntArray::length()  
  43. {  
  44.     return m_length;  
  45. }  
  46.   
  47. bool IntArray::get(int index, int& value)  
  48. {  
  49.     bool ret = (0 <= index) && (index < length());  
  50.       
  51.     if( ret )  
  52.     {  
  53.         value = m_pointer[index];  
  54.     }  
  55.       
  56.     return ret;  
  57. }  
  58.   
  59. bool IntArray::set(int index, int value)  
  60. {  
  61.     bool ret = (0 <= index) && (index < length());  
  62.       
  63.     if( ret )  
  64.     {  
  65.         m_pointer[index] = value;  
  66.     }  
  67.       
  68.     return ret;  
  69. }  
  70.   
  71. int& IntArray::operator [] (int index)  
  72. {  
  73.     return m_pointer[index];  
  74. }  
  75.   
  76. IntArray& IntArray::operator = (const IntArray& obj)  
  77. {  
  78.     ifthis != &obj )  
  79.     {  
  80.         int* pointer = new int[obj.m_length];  
  81.           
  82.         if( pointer )  
  83.         {  
  84.             for(int i=0; i<obj.m_length; i++)  
  85.             {  
  86.                 pointer[i] = obj.m_pointer[i];  
  87.             }  
  88.               
  89.             m_length = obj.m_length;  
  90.             delete[] m_pointer;  
  91.             m_pointer = pointer;  
  92.         }  
  93.     }  
  94.       
  95.     return *this;  
  96. }  
  97.   
  98. IntArray& IntArray::self()  
  99. {  
  100.     return *this;  
  101. }  
  102.   
  103. IntArray::~IntArray()  
  104. {  
  105.     delete[]m_pointer;  
  106. }  


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. }  


                    第36课 - 经典问题解析三


4、不积硅步无以至干里

            编译器默认提供的函数

        第36课 - 经典问题解析三


5、关于string的疑问

            下面的代码输出什么?为什么

  1. string s= "12345";   
  2.   
  3. const char* p = s. c_str() ;   
  4.   
  5. cout << p << endl;   
  6.   
  7. s.append ("abced") ;   
  8.   
  9. cout << p << endl;  


6、编程实验

字符串问题1     36-2.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();  
  10.           
  11.     cout << p << endl;       
  12.           
  13.     s.append("abced");  // p 成为了野指针  
  14.           
  15.     cout << p << endl;       
  16.   
  17.       
  18.     return 0;  
  19. }  


                第36课 - 经典问题解析三



            问题分析

        第36课 - 经典问题解析三

                    string对象内部维护了—个指向数据的char*指针,

                    这个指针可能在程序运行的过程中发生改变。


                            原来的空间被释放,p成了野指针

                    尽量不要混合C++编程方法和C语言编程方法



            下面的程序输出什么?为什么?

  1. const char* p = "12345";   
  2. string s = "";   
  3.   
  4. s.reserve (10);   
  5.   
  6. for(int i=O; i<5; i++)  
  7. {  
  8.     s[i] =p[i];  
  9.  }   
  10.   
  11.   
  12. if(!s.empty())  
  13. {  
  14.     cout << s << endl;  
  15. }  


7、编程实验

字符串问题2     36-3.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.     cout << s << endl;  
  20.       
  21.     return 0;  
  22. }  


                第36课 - 经典问题解析三


            问题分析

            第36课 - 经典问题解析三


8、小结

            在需要进行深拷贝的时候必须重载赋值操作符 

            赋值操作符和拷贝构造函数有同等重要的意义 

            string类通过—个数据空间保存字符数据 

            string类通过—个成员变量保存当前字符串的长度

             C++开发时尽量避开C语言中惯用的编程思患