赋值运算符重载

赋值运算符的重载在这几个默认的成员函数中的位置也算是举足轻重的,它也是不好理解的一个,

面是我自己写的一个复数类,这里面会将赋值运算符重载踏踏实实的过完。

赋值运算符的重载的基本格式:

operator + 合法的运算符 构成函数名(重载

class Complex

{

public:

Complex(double real = 0.0, double image = 0.0)

{

_real = real;

_image = image;

}

Complex(const Complex& com) //拷贝构造函数

{

cout << "compelx(Complex& com" << endl;

_real = com._real;

_image = com._image;

}

Complex Add(Complex &com)

{

Complex cmp;

cmp._real = _real + com._real;

cmp._image = _image + com._image;

return cmp;

}

Complex operator+(Complex &com)//重载加法

{

Complex cmp;

cmp._real = _real + com._real;

cmp._image = _image + com._image;

return cmp;

}

Complex& operator++() //前置加加

{

_real++;

_image++;

return *this;

}

Complex& operator++(int) //后置加加

{

Complex tmp(*this);

_real++;

_image++;

return tmp;

}

Complex operator-(Complex &com)//重载减法

{

Complex cmp;

cmp._real = _real - com._real;

cmp._image = _image - com._image;

return cmp;

}

//这里有一个问题,为什么重载等号时,要用引用呢??

Complex& operator=(Complex& c)//重载等号

{

cout << "0perator" << endl;

if (this != &c)

{

_real = c._real;

_image = c._image;

}

return *this;

}

Complex& operator+=(Complex &com)//重载加等

{

_real += com._real;

_image += com._image;

return *this;

}

~Complex()//析构函数

{

cout << "~Complex()" << endl;

}

void Display()//打印

{

cout << _real << "+" << _image << "i" << endl;

}

private:

double _real;

double _image;

};

int main()

{

Complex c1(1.0, 1.0);

Complex c2(2.0, 2.0);

c2 = c1; //等价于c2.operator=(c1); 只要你进行了重载后比如 c2=c1

c1++; //等价于c1.++(); 系统会默认为你重载后的形式++c1; //等价于c1.++(c1)

c2 += c1; //等价于c2.operator+=(c1)

c1.Display();

c2.Display();

return 0;

}

这是运行结果~:

有木有觉得很迷。。。。。

其实赋值运算符的重载并不是很难,但是这里有几个很重要的点,运算符重载函数里面的参数是很关键的。

还有你一定要注意参数的位置,以及想一想使用时函数的样子。

比如c1++ 你在使用它的时候你的脑子里想的要是 C1.++()这样出错的概率才会减少,你的程序严密性就会高。

下面来说赋值运算符重载如何使用!!!

1.参数

一般地,赋值运算符重载函数的参数是函数所在类的const类型的引用(如上面例1),加const是因为:

①我们不希望在这个函数中对用来进行赋值的“原版”做任何修改。

②加上const,对于const的和非const的实参,函数就能接受;如果不加,就只能接受非const的实参。

用引用是因为:

这样可以避免在函数调用时对实参的一次拷贝,提高了效率。

但是比如++运算符就不适合用const,const只是一个建议,它就是提升你文件的严密性

2.返回值

我在代码段中有这么一个问题。

这里有一个问题,为什么重载等号时,要用引用呢??

一般地,返回值是被赋值者的引用,即*this(如上面例1),原因是

①这样在函数返回时避免一次拷贝,提高了效率。

②更重要的,这样可以实现连续赋值,即类似a=b=c这样。如果不是返回引用而是返回值类型,那么,

执行a=b时,调用赋值运算符重载函数,在函数返回时,由于返回的是值类型,所以要对return后边的

“东西”进行一次拷贝,得到一个未命名的副本(有些资料上称之为“匿名对象”),然后将这个副

本返回,而这个副本是右值,所以,执行a=b后,得到的是一个右值,再执行=c就会出错。

3.赋值运算符重载函数要避免自赋值

对于赋值运算符重载函数,我们要避免自赋值情况(即自己给自己赋值)的发生,一般地,我们通过比较

赋值者与被赋值者的地址是否相同来判断两者是否是同一对象(正如例1中的if (this != &str)一句)。

为什么要避免自赋值呢?

①为了效率。显然,自己给自己赋值完全是毫无意义的无用功,特别地,对于基类数据成员间的赋值,还会

调用基类的赋值运算符重载函数,开销是很大的。如果我们一旦判定是自赋值,就立即return *this,会避免

对其它函数的调用。

②如果类的数据成员中含有指针,自赋值有时会导致灾难性的后果。对于指针间的赋值(注意这里指的是指针

所指内容间的赋值,这里假设用_p给p赋值),先要将p所指向的空间delete掉(为什么要这么做呢?因为指针

p所指的空间通常是new来的,如果在为p重新分配空间前没有将p原来的空间delete掉,会造成内存泄露),然

后再为p重新分配空间,将_p所指的内容拷贝到p所指的空间。如果是自赋值,那么p和_p是同一指针,在赋值

操作前对p的delete操作,将导致p所指的数据同时被销毁。那么重新赋值时,拿什么来赋?

所以,对于赋值运算符重载函数,一定要先检查是否是自赋值,如果是,直接return *this。

4.浅拷贝和深拷贝

拷贝构造函数和赋值运算符重载函数都会涉及到这个问题。

所谓浅拷贝,就是说编译器提供的默认的拷贝构造函数和赋值运算符重载函数,仅仅是将对象a中各个

数据成员的值拷贝给对象b中对应的数据成员(这里假设a、b为同一个类的两个对象,且用a拷贝出b或

用a来给b赋值),而不做其它任何事。

假设我们将例1中显式提供的拷贝构造函数注释掉,然后同样执行MyStr str3 = str2;语句,

此时调用默认的拷贝构造函数,它只是将str2的id值和nane值拷贝到str3,这样,str2和str3中的

name值是相同的,即它们指向内存中的同一区域(在例1中,是字符串”hhxx”)。如下图

这样,会有两个致命的错误

①当我们通过str2修改它的name时,str3的name也会被修改!

②当执行str2和str3的析构函数时,会导致同一内存区域释放两次,程序崩溃!

这是万万不可行的,所以我们必须通过显式提供拷贝构造函数以避免这样的问题。先判断被

拷贝者的name是否为空,若否,dalete name(后面会解释为什么要这么做),然后,为name重新申

请空间,再将拷贝者name中的数据拷贝到被拷贝者的name中。执行后,如图

这样,str2.name和str3.name各自独立,避免了上面两个致命错误。

我们是以拷贝构造函数为例说明的,赋值运算符重载函数也是同样的道理。

最后还有几个赋值运算符重载的几个小知识:

1.重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。

2.5个C++不能重载的运算符:  .*/ : : / sizeof / ?: /.

3.C++规定,赋值运算符重载函数只能是类的非静态的成员函数,不能是静态成员函数,也不能是友元函数

4.赋值运算符重载函数不能被继承

5.当程序没有显式地提供一个以本类或本类的引用为参数的赋值运算符重载函数时,编译器会自动生成这样一

个赋值运算符重载函数。

在c++语言中赋值运算符,C++语言— 类中的赋值运算符重载相关推荐

  1. C++多继承中重写不同基类中相同原型的虚函数

    在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA  {  public:  virtual void TestA();  };  class ...

  2. 将Frock类声明为抽象类,尺寸在Frock类中定义,在类中声明抽象方法calcArea方法,用来计算衣服的布料面积。

    将Frock类声明为抽象类,尺寸在Frock类中定义,在类中声明抽象方法calcArea方法,用来计算衣服的布料面积. 编写Shirt类继承Frock类,实现 calcArea方法,用来计算衬衣所需的 ...

  3. 为什么wait、notify、notifyAll方法定义在Object中而不是Thread类中

    多线程概述 Java是一个支持多线程的开发语言,多线程并发执行任务可以充分利用CPU资源,提高多任务并发执行效率(注意区分:多线程并不会加快任务的执行速度,而是可以充分利用多核CPU让线程轮流进行工作 ...

  4. 【Groovy】闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )

    文章目录 总结 一.接口中定义 call() 方法 二.类中定义 call() 方法 三.完整代码示例 总结 在 实例对象后使用 " () " 括号符号 , 表示调用该实例对象的 ...

  5. Android中怎样在工具类中获取Context对象

    场景 Android程序中访问资源时需要提供Context,一般来说只有在各种component中(Activity, Provider等等)才能方便的使用api来获取Context对象, 如果在编写 ...

  6. Winform中怎样在工具类中对窗体中多个控件进行操作(赋值)

    场景 需求是在窗体加载完成后掉用工具类的方法,工具类中获取窗体的多个控件对象进行赋值. 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 ...

  7. static在php中,php中static关键字在类中的使用

    static关键字用来修饰属性.方法,称这些属性.方法为静态属性.静态方法. static关键字声明一个属性或方法是和类相关的,而不是和类的某个特定的实例相关,因此,这类属性或方法也称为"类 ...

  8. python中arcsec_在Python类中继承Cython类

    我有两个用cython编写的类,我想在python中的一个类中使用它们.在 位置.pyximport numpy as np cimport numpy as np cimport cython cp ...

  9. MFC开发过程中,自定义的类中做分割窗口的图像显示,GetDC出现问题:function does not take 0 parameters?

    做MFC分割窗口时,其中含有视类CxxVew窗口,含有General Class (自定义的类CMyXX),在CMyXX中使用GetDC时: CDC* pDC = GetDC(); 出现标题中的问题, ...

  10. 【无为则无心Python基础】— 62、Python中私有成员方法(类中行为的封装)

    Python对于类的成员没有严格的访问控制限制,这与其他面向对象的编程语言是有所区别的. 关于私有方法其实和私有属性差不多,有如下要点: 1.通常我们约定,两个下划线开头的方法是私有方法. 2.类内部 ...

最新文章

  1. delegate、Lambda表达式、Func委托和Expression(TDelegate)表达式目录树
  2. 我慌了!技术经理问为什么要分布式存储......
  3. PING检查网络是否畅通
  4. npm 安装less插件_IDEA编译less插件LESS CSS Compiler的安装
  5. 《转》Android 今日头条屏幕适配方案终极版正式发布!
  6. python 读取excel 生成json 读取json
  7. 【java学习之路】(java SE篇)008.集合
  8. 用nmap扫描内网conficker
  9. 什么是云渲染?【云渲染和传统渲染农场的区别】
  10. Java自学经验分享
  11. 怎么把照片变年轻?这两个照片变年轻小妙招教给你
  12. QGraphicsItem图元的简单使用(一)
  13. 某注册页面存在手机短信验证码绕过
  14. 掌门少儿打造高质课程,助力少年儿童全方位发展
  15. 《Kaggle》Tweet Sentiment Extraction 实战(一)构建数据加载器
  16. 面试后说hold什么意思_面试快结束时,如果面试官对你说这几句话,说明你被淘汰了!...
  17. 【答读者问26】量化投资框架哪家强?backtrader vs zipline vs 聚宽 vs 米筐
  18. 计算机文件管理word,WORD打开文件的方式和管理文件-word技巧-电脑技巧收藏家
  19. xset 关闭屏幕保护-关闭节电模式
  20. ElasticSearch保姆级入门教程

热门文章

  1. thinkphp 二级域名绑定模块,导致设置的路由被多域名共用的问题解决方案
  2. MySQL------报错Access denied for user ‘root‘@‘localhost‘ (using password:NO)解决方法
  3. Eclipse启动Tomcat,45S超时问题解决
  4. 【干货】陆奇:新格局下的创业创新机会.pdf(附下载链接)
  5. 大学生研究生必备的数据竞赛平台
  6. 重磅福利!程序员面试——算法工程师面试大全第五部分
  7. vuex commit 模块_分享一个Vuex的使用的新姿势
  8. 安卓application_安卓系统蓝牙配对流程分析
  9. WMS仓储管理系统有那些功能?
  10. 解决chrome/Edge提示您的连接不是私密连接的方法