C++中的赋值操作符重载和拷贝构造函数

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 循环之类的;

此文为作者学习唐佐林老师的学习笔记,仅为交流共享之用,由此带来的后果,与作者无关;转载请注明转载出处;难免有错,欢迎指正,联系方式qunchao24@sina.com。
posted @ 2021-04-23 09:26  恋恋西风  阅读(259)  评论(0编辑  收藏  举报