为数偶类定义专用的赋值操作符
class Couple { public: Couple(int a = 0, int b = 0) :_a(a), _b(b) {} Couple(const Couple &c):_a(c._a),_b(c._b){} Couple &operator=(const Couple &c); private: int _a, _b; }; Couple & Couple::operator=(const Couple &c) { if (*this == c)//在不同的情况下,此语句可能会降低程序的执行的效率,比如多数情况下赋值的不是对象自身,因此要根据情况判定; { return *this; } _a = c._a; _b = c._b; return *this; } int main() { Couple a(1, 2), b(2, 3); cout << a << endl; a = b; cout << a << endl; return 0; }
为数偶类定义专用的简写四则运算符
class Couple { public: Couple(int a = 0, int b = 0) :_a(a), _b(b) {} Couple(const Couple &c) :_a(c._a), _b(c._b) {} Couple &operator+=(const Couple &c); Couple &operator*=(const Couple &c); Couple &operator*=(const int &k); private: int _a, _b; }; Couple & Couple::operator+=(const Couple &c) { _a += c._a; _b += c._b; return *this; } Couple & Couple::operator*=(const Couple &c) { _a *= c._a; _b *= c._b; return *this; } Couple & Couple::operator*=(const int &k) { _a *= k; _b *= k; return *this; }
为数偶类定义专用的递增递减操作符
class Couple { public: Couple(int a = 0, int b = 0) :_a(a), _b(b) {} Couple(const Couple &c) :_a(c._a), _b(c._b) {} Couple & operator=(const Couple &c); Couple & operator++();//前缀递增,返回本对象的引用 Couple operator++(int);//后缀递增,返回本对象的拷贝 private: int _a, _b; }; Couple & Couple::operator++() { ++_a, ++_b; return *this; } Couple Couple::operator++(int _t) { Couple _t(*this); _a++, _b++; return _t; }
赋值操作符的返回值
- 除后缀递增递减操作符,应返回对象的引用,以与C++本身的语义相符合
- 返回对象需要额外的对象构造,降低效率
- 如果不需要返回值以进行连续赋值,可以将返回值设为void,但要注意此时重载的操作符语义与C++不符合,故不推荐
赋值构造与拷贝构造
赋值也是构造
拷贝、赋值与析构三位一体,一般同时出现
- 缺省赋值构造与拷贝构造为浅拷贝
- 如果对象没有指针成员,缺省行为即可满足要求,无需实现或重载这三个函数
- 如果对象有指针成员,一般需要重载这三个函数
浅拷贝
class A { public: A():_n(0),_p(NULL){} explicit A(int n) :_n(n), _p(new int[n]) {}//把数组的基地址赋值给_p A(int n, int *p) :_n(n), _p(p) {} //如果省略以下语句,编译器自动生成以下两条语句(浅拷贝) A(const A & that) :_n(that._n), _p(that._p) {}//浅拷贝 A & operator=(const A & that) { _n = that._n, _p = that._p; return *this; } virtual ~A() { if (_p) { delete[]_p; _p = NULL; } } public: int & operator[](int i); const int & operator[](int i) const; private: int _n; int *_p; }; int & A::operator[](int i) { if (i < 0 || i >= 4) throw std::out_of_range("Out of range when trying to access the object... "); return _p[i]; } const int & A::operator[](int i) const { if (i < 0 || i >= 4) throw std::out_of_range("Out of range when trying to access the object.."); return _p[i]; } int main() { A a(4), b; for ( int i = 0; i < 4; i++) { a[i] = i + 1; } std::cout << "Before object assignment:" << std::endl; for (int i = 0; i < 4; i++) { std::cout << a[i] << " "; } std::cout << std::endl; b = a; std::cout << "After object assignment:" << std::endl; for (int i = 0; i < 4; i++) { std::cout << b[i] << " "; } std::cout << std::endl; return 0;//程序结束时,系统崩溃 }
对象a是main函数中定义的局部变量,当程序结束时对象a的_p会释放其指向的目标存储区,而对象b同样会去销毁目标存储区,但是目标存储区已被释放,此时出现了空悬指针;导致b在销毁对象使用delete[]时,程序崩溃;
解决方法:
- 使用深拷贝(拷贝一份指针指向目标数据对象的副本)
class A { public: A():_n(0),_p(NULL){} explicit A(int n) :_n(n), _p(new int[n]) {}//把数组的基地址赋值给_p A(int n, int *p) :_n(n), _p(p) {} A(const A & that); A & operator=(const A & that); virtual ~A() { if (_p) { delete[]_p; _p = NULL; } } public: int & operator[](int i); const int & operator[](int i) const; private: int _n; int *_p; }; A::A(const A & that)//拷贝构造函数 { this->_n = that._n; _p = new int[_n]; for (int i = 0; i < _n; i++) { _p[i] = that._p[i]; } } A & A::operator=(const A & that)//重载赋值运算符 { this->_n = that._n; if (_p) { delete[]_p; } _p = new int[_n]; for (int i = 0; i < _n; i++) { _p[i] = that._p[i]; } return *this; }
注意:在赋值操作时本对象其实已经存在,_P可能指向一个有意义的数组,数组在赋值操作后即失去意义,所以要先删除_p指向的目标数组,然后对它进行创建连续的存储区,一个一个元素地拷贝;