第36课 - 经典问题解析三
1、关于赋值的疑问
什么时候需要重载赋值操作符?
编译器是否提供默认的赋值操作?
编译器为每个类默认重载了赋值操作符
默认的赋值操作符仅完成浅拷贝
当需要进行深拷贝时必须重载赋值操作符
赋值操作符与拷贝构造函数有相同的存在意义
2、编程实验
默认赋值操作符重载 36-1.cpp
- #include <iostream>
- #include <string>
- using namespace std;
- class Test
- {
- int* m_pointer;
- public:
- Test()
- {
- m_pointer = NULL;
- }
- Test(int i)
- {
- m_pointer = new int(i);
- }
- Test(const Test& obj)
- {
- m_pointer = new int(*obj.m_pointer);
- }
- Test& operator = (const Test& obj)
- {
- if( this != &obj )
- {
- delete m_pointer;
- m_pointer = new int(*obj.m_pointer);
- }
- return *this;
- }
- void print()
- {
- cout << "m_pointer = " << hex << m_pointer << endl;
- }
- ~Test()
- {
- delete m_pointer;
- }
- };
- int main()
- {
- Test t1 = 1;
- Test t2;
- t2 = t1;
- t1.print();
- t2.print();
- return 0;
- }
当初始化赋值时,即:Test t2 = t1 时调用的是默认拷贝构造
问题分析
—般性原则
重载赋值操作符,必然需要实现深拷贝!3、编程实验
数组类的优化 IntArray.cpp
IntArray.h
- #ifndef _INTARRAY_H_
- #define _INTARRAY_H_
- class IntArray
- {
- private:
- int m_length;
- int* m_pointer;
- IntArray(int len);
- IntArray(const IntArray& obj);
- bool construct();
- public:
- static IntArray* NewInstance(int length);
- int length();
- bool get(int index, int& value);
- bool set(int index ,int value);
- int& operator [] (int index);
- IntArray& operator = (const IntArray& obj);
- IntArray& self();
- ~IntArray();
- };
- #endif
IntArray.cpp
- #include "IntArray.h"
- IntArray::IntArray(int len)
- {
- m_length = len;
- }
- bool IntArray::construct()
- {
- bool ret = true;
- m_pointer = new int[m_length];
- if( m_pointer )
- {
- for(int i=0; i<m_length; i++)
- {
- m_pointer[i] = 0;
- }
- }
- else
- {
- ret = false;
- }
- return ret;
- }
- IntArray* IntArray::NewInstance(int length)
- {
- IntArray* ret = new IntArray(length);
- if( !(ret && ret->construct()) )
- {
- delete ret;
- ret = 0;
- }
- return ret;
- }
- int IntArray::length()
- {
- return m_length;
- }
- bool IntArray::get(int index, int& value)
- {
- bool ret = (0 <= index) && (index < length());
- if( ret )
- {
- value = m_pointer[index];
- }
- return ret;
- }
- bool IntArray::set(int index, int value)
- {
- bool ret = (0 <= index) && (index < length());
- if( ret )
- {
- m_pointer[index] = value;
- }
- return ret;
- }
- int& IntArray::operator [] (int index)
- {
- return m_pointer[index];
- }
- IntArray& IntArray::operator = (const IntArray& obj)
- {
- if( this != &obj )
- {
- int* pointer = new int[obj.m_length];
- if( pointer )
- {
- for(int i=0; i<obj.m_length; i++)
- {
- pointer[i] = obj.m_pointer[i];
- }
- m_length = obj.m_length;
- delete[] m_pointer;
- m_pointer = pointer;
- }
- }
- return *this;
- }
- IntArray& IntArray::self()
- {
- return *this;
- }
- IntArray::~IntArray()
- {
- delete[]m_pointer;
- }
main.cpp
- #include <iostream>
- #include <string>
- #include "IntArray.h"
- using namespace std;
- int main()
- {
- IntArray* a = IntArray::NewInstance(5);
- IntArray* b = IntArray::NewInstance(10);
- if( a && b )
- {
- IntArray& array = a->self();
- IntArray& brray = b->self();
- cout << "array.length() = " << array.length() << endl;
- cout << "brray.length() = " << brray.length() << endl;
- array = brray;
- cout << "array.length() = " << array.length() << endl;
- cout << "brray.length() = " << brray.length() << endl;
- }
- delete a;
- delete b;
- return 0;
- }
4、不积硅步无以至干里
编译器默认提供的函数
5、关于string的疑问
下面的代码输出什么?为什么
- string s= "12345";
- const char* p = s. c_str() ;
- cout << p << endl;
- s.append ("abced") ;
- cout << p << endl;
6、编程实验
字符串问题1 36-2.cpp
- #include <iostream>
- #include <string>
- using namespace std;
- int main()
- {
- string s = "12345";
- const char* p = s.c_str();
- cout << p << endl;
- s.append("abced"); // p 成为了野指针
- cout << p << endl;
- return 0;
- }
问题分析
string对象内部维护了—个指向数据的char*指针,
这个指针可能在程序运行的过程中发生改变。
原来的空间被释放,p成了野指针
尽量不要混合C++编程方法和C语言编程方法
下面的程序输出什么?为什么?
- const char* p = "12345";
- string s = "";
- s.reserve (10);
- for(int i=O; i<5; i++)
- {
- s[i] =p[i];
- }
- if(!s.empty())
- {
- cout << s << endl;
- }
7、编程实验
字符串问题2 36-3.cpp
- #include <iostream>
- #include <string>
- using namespace std;
- int main()
- {
- const char* p = "12345";
- string s = "";
- s.reserve(10);
- // 不要使用 C 语言中的方式操作 C++ 中的字符串
- for(int i=0; i<5; i++)
- {
- s[i] = p[i];
- }
- cout << s << endl;
- return 0;
- }
问题分析
8、小结
在需要进行深拷贝的时候必须重载赋值操作符
赋值操作符和拷贝构造函数有同等重要的意义
string类通过—个数据空间保存字符数据
string类通过—个成员变量保存当前字符串的长度 C++开发时尽量避开C语言中惯用的编程思患