为数偶类定义专用的赋值操作符

class Couple
{
public:
Couple(int a = , int b = ) :_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(, ), b(, );
cout << a << endl;
a = b;
cout << a << endl;
return ;
}

为数偶类定义专用的简写四则运算符

class Couple
{
public:
Couple(int a = , int b = ) :_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 = , int b = ) :_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(),_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 < || i >= )
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 < || i >= )
throw std::out_of_range("Out of range when trying to access the object..");
return _p[i];
} int main()
{
A a(), b;
for ( int i = ; i < ; i++)
{
a[i] = i + ;
}
std::cout << "Before object assignment:" << std::endl;
for (int i = ; i < ; i++)
{
std::cout << a[i] << " ";
}
std::cout << std::endl;
b = a;
std::cout << "After object assignment:" << std::endl;
for (int i = ; i < ; i++)
{
std::cout << b[i] << " ";
}
std::cout << std::endl;
return ;//程序结束时,系统崩溃
}

对象a是main函数中定义的局部变量,当程序结束时对象a的_p会释放其指向的目标存储区,而对象b同样会去销毁目标存储区,但是目标存储区已被释放,此时出现了空悬指针;导致b在销毁对象使用delete[]时,程序崩溃;

解决方法:

  • 使用深拷贝(拷贝一份指针指向目标数据对象的副本)

class A
{
public:
A():_n(),_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 = ; 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 = ; i < _n; i++)
{
_p[i] = that._p[i];
}
return *this;
}

注意:在赋值操作时本对象其实已经存在,_P可能指向一个有意义的数组,数组在赋值操作后即失去意义,所以要先删除_p指向的目标数组,然后对它进行创建连续的存储区,一个一个元素地拷贝;

C++学习笔记12:运算符重载(赋值操作符1)的更多相关文章

  1. C++学习笔记之运算符重载

    一.运算符重载基本知识 在前面的一篇博文 C++学习笔记之模板(1)——从函数重载到函数模板 中,介绍了函数重载的概念,定义及用法,函数重载(也被称之为函数多态)就是使用户能够定义多个名称相同但特征标 ...

  2. C++基础 学习笔记五:重载之运算符重载

    C++基础 学习笔记五:重载之运算符重载 什么是运算符重载 用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载.运算符重载是静态多态性的体现. 运算符重载的规则 重载公式 ...

  3. Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)

    问题聚焦: 这个准则比较简短,但是往往就是这种细节的地方,可以提高你的代码质量. 细节决定成败,让我们一起学习这条重载赋值操作符时需要遵守的准则吧. 还是以一个例子开始: Demo // 连锁赋值 x ...

  4. matlab学习笔记12单元数组和元胞数组 cell,celldisp,iscell,isa,deal,cellfun,num2cell,size

    一起来学matlab-matlab学习笔记12 12_1 单元数组和元胞数组 cell array --cell,celldisp,iscell,isa,deal,cellfun,num2cell,s ...

  5. C++ 之 重载赋值操作符

    Widget 类中,定义了一个 Bitmap 类型的私有数据成员 -- pb 指针 class Bitmap { ... }; class Widget { private: Bitmap *pb; ...

  6. C++中复制构造函数与重载赋值操作符总结

    前言 这篇文章将对C++中复制构造函数和重载赋值操作符进行总结,包括以下内容: 1.复制构造函数和重载赋值操作符的定义: 2.复制构造函数和重载赋值操作符的调用时机: 3.复制构造函数和重载赋值操作符 ...

  7. Ext.Net学习笔记12:Ext.Net GridPanel Filter用法

    Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...

  8. C++中复制构造函数与重载赋值操作符

    我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数.析构函数.复制构造函数和重载赋值操作:即使在你没有明确定义的情况下,编译器也会给你生成这样的四个函数.例如以下类:   class CTe ...

  9. SQL反模式学习笔记12 存储图片或其他多媒体大文件

    目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点:     1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...

  10. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

随机推荐

  1. bat产生随机数并复制文件及生成文件列表

    有这样一个场景:我需要将同一个文件复制为上千个文件,并且文件名应为随机数.为了简单起见,不想写程序,直接写个BAT来,方便,简单,易用: 1. 搞定用BAT产生32位随机数,存为变量并使用,保存以下代 ...

  2. 介绍开源的.net通信框架NetworkComms

    Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  开源地址是:https://github.com/MarcFletcher/ ...

  3. php中日期的加减法运算

    需求:通过对某个日期增加或减去几天,得到另外一个日期1.首先通过strtotime()获得日期的时间戳2.获得N天前得时间戳,通过”当前时间戳 - N天的秒数 = N天前得时间戳“3.对N天前得时间戳 ...

  4. (DFS)zoj1008-Gnome Tetravex

    现在zoj暂时关了,实际上是在scuoj上做的. 题目地址 看起来题目比较复杂,实际上主要需要思维的是如何恰当的剪枝及合适的DFS角度. 问题等价于将n*n个可能相同的方块放到一个n*n的表中,使满足 ...

  5. IP数据报的格式

    1. IP数据报首部的固定部分中的各字段 ①版本:占4位,指IP协议的版本.通信双方使用的 IP协议版本必须一致.日前广泛使用的 IP协议版本号为 4 (即 IPv4). IPv6 目前还处于起步阶段 ...

  6. Right-BICEP 测试四则运算二程序

    测试方法: Right-BICEP 测试计划: 1.Right-结果是否正确? 2.B-是否所有的边界条件都是正确的? 3.是否有乘除法? 4.是否有括号? 5.是否有输出方式? 6.是否可以选择出题 ...

  7. C/C++类型转换总结

    ---恢复内容开始--- 最近做笔试题经常会碰到有关类型转换的题型,所以结合例子做下总结,也是希望自己能更时刻的理解类型转换. C++的类型转换包括内置类型和类类型对象的转换. (1) 1.1隐式类型 ...

  8. JS constructor

    1.每个对象都有一个constructor,都指向创建该对象的方法. 2.function对象的prototype的constructor也是指向该方法.如果对prototype进行重写,constr ...

  9. hdu3473 线段树 划分树

    //Accepted 28904 KB 781 ms //划分树 //所求x即为l,r区间排序后的中位数t //然后求出小于t的数的和sum1,这个可以用划分树做 //求出整个区间的和sum,可以用O ...

  10. How to Avoid OOM in Android

    1.use java reference(strong soft weak phantom) 2.use android:largeHeap="true" above or VMR ...