目录

1、什么是运算符重载?

2、重载运算符的限制

3、运算符重载函数的总结

4、实现复数的各类运算符重载

(1)通过函数来实现复数相加

(2)通过运算符“+”重载来实现复数相加

(3)通过运算符 “*” “/” 实现复数乘除

(4)重载“=”

5、运算符重载返回类型

(1)运算符重载实现前置++与后置++

(2)值返回与引用返回

用引用作为返回值,省去了拷贝构造和析构,可以避免一些无端的开销

6、默认拷贝构造函数

有指针作为数据成员不能用默认拷贝

如果调用默认的赋值重载,则让p2的指针重新指向了p1,两指针指向同一块空间,但p2原本的空间仍在

7、模拟string功能


1、什么是运算符重载?

运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

让类类型的对象像基本数据类型一样去操作  例如:可以实现对象+,-* / % == ! = [] () << >>

运算符的重载实际是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该重载的运算符时调用此函数。这个函数叫做运算符重载函数,通常为类的成员函数。

定义运算符重载函数的一般格式:

返回值类型 类名::operator重载的运算符(参数表) {……}

operator是关键字,它与重载的运算符一起构成函数名。因函数名的特殊性,C++编译器可以将这 类函数识别出来。

2、重载运算符的限制

(1)不可臆造新的运算符.

(2)不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数.

(3)运算符重载不宜使用过多.

(4)重载运算符含义必须清楚,不能有二义性.

(5)C++允许重载的运算符绝大部分运算符可以重载。

不能重载的运算符只有5个:成员访问运算符、成员指针访问运算符(*)、域运算符(::)、长度运算符(sizeof)、条件运算符(?:)

(6)重载运算符的函数不能有默认的参数。

(7)重载的运算符必须和用户定义的类型的对象一起使用,其参数至少应有一个是类的对象(或类对象的引用)。

(8)用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”不必用户重载。

(9)从理论上说,可以将一个运算符重载为执行任意的操作。如,将“>”运算符重载为“<”运算,但这样违背了运算符重载的初衷,非但没有提高可读性,反而使人无法理解程序。应当是重载运算符的功能类似于该运算符作用于标准类型时所能实现的功能。

3、运算符重载函数的总结

1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右 操作数作为函数的实参。

2、当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个 或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。

3、单目运算符“++”和“--”存在前置与后置问题。 前置“++”格式为: 返回类型 类名::operator++(){……} 而后置“++”格式为: 返回类型 类名::operator++(int){……} 后置“++”中的参数int仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。

4、C++中只有极少数的运算符不允许重载。

还有 # , ## , // , / * */

4、实现复数的各类运算符重载

(1)通过函数来实现复数相加

Complex Add(Complex cx) // 第一种写法
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}// 这里采用Complex对象的引用而不是对象本身,
// 调用时不再重新分配内存建立一个复制的对象,函数效率会更高。
Complex Add(Complex &cx) // 第二种写法
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}//而在引用形式参数类型说明前加const关键字,表示被引用的实参是不可改变的,
//如程序员不当心在函数体中重新赋值了被引用的实参, C++编译器会认为出错。
Complex Add(const Complex &cx) // 第三种写法
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}// 成员函数为常方法,如程序员不当心在函数体中对当前对象重新赋值,
// C++编译器会认为出错。
Complex Add(const Complex &cx) const // 第四种写法
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}// 不要使用引用返回tmp对象,当函数执行结束后,tmp 对象析构了,
//会产生将亡值
Complex & Add(const Complex &cx) const // 第五种写法
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}

(2)通过运算符“+”重载来实现复数相加

Complex operator+(const Complex& cx) const
{
Complex tmp(Real + cx.Real, Image + cx.Image);
return tmp;
}

(3)通过运算符 “*” “/” 实现复数乘除

//复数乘法: (a+bi) * (c+di) => (a*c - b*d) +(b*c + a*d)i;
//复数除法: (a+bi) /(c+di)
d = c*c + d*d;
x = (a*c + b*d)/d + (b*c - a*d)i;
Complex Complex::operator*(const Complex & c) const
{//重载*
return Complex(Real*c.Real-Image*c.Image,Real*c.Image+c.Real*Image);
}
Complex Complex::operator/(const Complex & c)
{ //重载/
double d = c.Real*c.Real+c.Image*c.Image ;
return Complex((Real*c.Real+Image*c.Image)/d,(Image*c.RealReal*c.Image)/d) ;
}

(4)重载“=”

在类定义中如果没有显式给出赋值运算符重载函数时,并不是不用赋值函数,而是由系统自动调用 缺省的赋值函数。

//赋值语句重载
Complex & operator=(const Complex& cx)
{if (this != &cx){this->Real = cx.Real;this->Image = cx.Image;}cout << this << "operator=" << &cx << endl;
}
//c1=c2=c3
//c1=c2.operator=(c3)
//c1=operator=(&c2,c3)

5、运算符重载返回类型

两种类型:值返回,引用返回

(1)只能作为表达式的右边,则必须值返回  a+b  a-b  a*b  a/b

(2)如果可以作为赋值表达式的左边,建议引用返回  a=b  a[4]  cout<<a

void main()
{int a = 10, b = 3;int c = 0;c = a + b;//从a内存空间取出a,从b内存空间取出b,进行相加,放到左边c的内存空间中去//a+b=c//error,左边为临时空间,不能存放c的值++a = 13;//返回对象本身,未开辟临时空间,将c放到a的存储空间cout << a << endl;//b++ = 13;//error,存在临时空间//前++引用返回,后++值返回
}

(1)运算符重载实现前置++与后置++

//返回的是+1操作之后的值的引用,是一个左值
Int &operator ++()//返回的是引用
{value += 1;return *this;
}
//返回+1操作之前的值的副本,是一个右值
//看起来先使用后+1,实际上它已经+1了,只不过我们使用的是它+1之前的值
Int operator++(int)//返回的是值
{Int tmp = *this;++* this;//调用前置++return tmp;
}

从代码可以看出,前置++比后置++效率高,不用产生临时对象,不用调用拷贝构造函数

后置++运算符重载,注意需要加int来与前置++重载做区分,语法规定

后置++返回的是值而不是引用,因为不可以返回局部变量

后置++是先将a放到寄存器中,返回的是右值

(2)值返回与引用返回

class A
{
public:A(int i=0):m_i(i){}void Print(){cout << m_i << endl;}A operator+(const A &b)//a.operator+(b)  本质即是实现对象的数据成员的加法{return m_i + b.m_i;}A operator-(const A& s)//b.operator-(a)  s接收第二个操作数{return this->m_i - s.m_i;}A& operator++()//a.++(){++m_i;//将a自己的数据成员进行修改,修改完后返回自己本身return *this;}/** b++,表达式的值是b没有加之前的值,表达式执行完后,b的值变成+1之后的值,所以重载后++时,得体现两种值*/A operator++(int)//c++规定在后++的时候,参数里面写个int,这个int没有实际作用,只是为了区分前++{//int t = m_i;//先保存以前的值//m_i = m_i + 1;//return t;//返回没加以前保存的值return m_i++;}
private:int m_i;
};
void main()
{A a(2), b(6);(a + b).Print();//a.+(b)  +(a,b)(b - a).Print();(++a).Print();//a.++()(b++).Print();//不能调用A operator++(),表达式b++的值是b没加之前的值 6b.Print();//b的值是上面加之后的值  7
}

用引用作为返回值,省去了拷贝构造和析构,可以避免一些无端的开销

class A
{
public:A(int i=0):m_i(i){}void Print(){cout << m_i << endl;}A& operator+(A& t){m_i = m_i + t.m_i;//this->m_i=this->m_i+b.m_i  a.m_i=a.m_i+b.m_ireturn *this;//return a}
private:int m_i;
};
//a+b=c,要如此写,a+b必须有确定的内存单元,可以将结果放到a或者b中去
void main()
{A a(7), b(10);(a + b).Print();((a + b) = 6).Print();
}

6、默认拷贝构造函数

如果程序员没有提供赋值运算符重载,则类会提供一个默认的,默认的功能为:

class A
{
public:A(int i=0,int j=0):m_i(i),m_j(j){}void Print(){cout << m_i << m_j << endl;}
private:int m_i;int m_j;
};
void main()
{A a(2, 6);A b;a.Print();// 2 6b.Print();// 0 0b = a;//用a的值重新给b赋值,调用了默认的赋值运算符重载函数b.Print();
}

如果有指针作为数据成员,则赋值运算符重载也要写出来,让两个不同的对象的指针分别指向内存单元,不过里面的内容保持相同

有指针作为数据成员不能用默认拷贝

如果调用默认的赋值重载,则让p2的指针重新指向了p1,两指针指向同一块空间,但p2原本的空间仍在

class Person
{
public:Person(const char *name="\0") {m_name = new char[strlen(name) + 1];strcpy_s(m_name, strlen(name) + 1, name);}void Print(){cout << m_name << endl;}~Person(){delete[]m_name;m_name = NULL;}Person& operator=(const Person& s){if (this == &s)//判断自赋值return *this;delete[]m_name;//接着开辟和右边对象s相同大小的内存单元m_name = new char[strlen(s.m_name) + 1];strcpy_s(m_name, strlen(s.m_name) + 1, s.m_name);return *this;}
private:char* m_name;
};
void main()
{Person p1("lisi");Person p2;p1.Print();//listp2.Print();//\0p2 = p1;//用p1给p2重新赋值  指向同一空间//如果调用默认的赋值重载,则让p2的指针重新指向了p1,两指针指向同一块空间,但p2原本的空间仍在p2.Print();
}

7、模拟string功能

class STR
{
public:STR(const char* str = "\0"){m_str = new char[strlen(str) + 1];strcpy_s(m_str, strlen(str) + 1, str);}STR (const STR& s){m_str = new char[strlen(s.m_str) + 1];strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);}~STR(){if (m_str != NULL){delete[]m_str;m_str = NULL;}}STR operator+(const STR& s)//两个对象中的字符串合并{char* temp = new char[strlen(m_str) + strlen(s.m_str) + 1];strcpy_s(temp, strlen(m_str)+1, m_str);strcat_s(temp,strlen(m_str)+strlen(s.m_str)+1, s.m_str);STR ss(temp);delete[]temp;temp = NULL;return ss;/* STR ss;//有问题delete[]ss.m_str;ss.m_str= new char[strlen(m_str) + strlen(s.m_str) + 1];strcpy_s(ss.m_str, strlen(m_str) + 1, m_str);strcat_s(ss.m_str, strlen(m_str) + strlen(s.m_str) + 1, s.m_str);return ss;*/}STR& operator=(const STR& s){if (this == &s)return *this;delete[]m_str;m_str = new char[strlen(s.m_str) + 1];strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);return *this;}void Print(){cout << m_str << endl;}char& operator[](int index){if (index < 0||index >(strlen(m_str)))exit(-1);return m_str[index];}bool operator==(const STR& s){if (strcmp(m_str, s.m_str) == 0){cout << "yes" << endl;return true;}else{cout << "no" << endl;return false;}}
private:char* m_str;
};
void main()
{STR a("111"), b("222");STR c = a + b;//a+b 拷贝构造STR d;d = c;//重新给d赋值,运算符重载c.Print();d.Print();c[5] = 'h';//c.[]5cout<< c[5] << endl;cout <<( a == b )<< endl;
}

C++——运算符的重载相关推荐

  1. C++——运算符的重载---以成员函数方式重载---以友元函数方式重载

    一.运算符的重载 1.运算符的重载 允许把标准运算符(如+ - * /等运算符)应用于自定义数据类型的对象,可以提高程序的可读性,运算符的重载本质上还是函数重载.运算符仅仅是语法上的方便,它是另一种函 ...

  2. C++知识点43——解引用运算符和箭头运算符的重载及智能指针类的实现

    一.概念. 在自定义行为类似指针的类时,需要重载*和->.C++中的智能指针就重载了这两个运算符.->必须是成员函数,*也应该是成员函数.与内置类型保持一致,这两个函数通常都是const的 ...

  3. C++知识点42——下标运算符[]的重载及string类的实现

    一.下标运算符的重载 1.概念 如果一个类表示容器,那么要重载下标运算符[],下标运算符必须是成员函数.下表访问运算符通常要有一个const版本和一个非const版本.如果不定义const版本,那么c ...

  4. C++知识点41——运算符的重载概念与分数类实现(下)

    接上篇文章https://blog.csdn.net/Master_Cui/article/details/109515571继续实现分数类和相关运算符的重载 6.自增自减运算符(++ --)的重载 ...

  5. C++知识点40——运算符的重载概念与分数类实现(中)

    接上篇文章https://blog.csdn.net/Master_Cui/article/details/109515376,继续实现分数类和相关运算符的重载 3.重载算术运算符和复合赋值运算符 算 ...

  6. C++知识点39——运算符的重载概念与分数类实现(上)

    一.概念 在博客https://blog.csdn.net/Master_Cui/article/details/109461561已经提到了赋值运算符的重载,重载运算符是有特殊名字的函数:名字由op ...

  7. C++——重载运算符和重载函数

    重载运算符和重载函数 C++ 中的函数重载 C++ 中的运算符重载 C++ 一元运算符重载 C++ 二元运算符重载 C++ 关系运算符重载 C++ 输入/输出运算符重载 C++ 赋值运算符重载 C++ ...

  8. c++学习笔记之运算符的重载

    运算符的重载包括双目运算符+的重载和输入输出流运算符的重载. 代码的功能是实现2行3列矩阵的加法 代码如下 #include<iostream> using namespace std; ...

  9. C++双目/单目运算符的重载

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105148178 双 ...

  10. 【C++】字符串中运算符的重载问题

    字符串中运算符的重载问题 运算符的重载: 运算符的重载实际是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该重载的运算符时调用此函数.这个函数叫做运算符重载函数,通常为类的成员函数. ...

最新文章

  1. JAVA就业指导(转)
  2. MEF程序设计指南七:使用目录(Catalog)动态装载xap与目录筛选(Filtered Catalog)...
  3. pandas修改数据类型_如何正确在pandas里使用inplace参数
  4. 文献学习(part17)--Correlation Adaptive Subspace Segmentation by Trace Lasso
  5. trunk口_什么是Trunk?Trunk详解
  6. 使用Apache + knewcode,用传统C++构建Web网站
  7. 每周学习总结11月9日
  8. 跟我一起学Windows Workflow Foundation(4)-----使用Listen,Delay,和其他envnt-based定制活动...
  9. 远程移动设备平台STF搭建指南
  10. 2017博鳌亚洲青年论坛(香港)顺利召开 中国发展人工智能优势在哪?
  11. 网易云课堂课程下载教程
  12. 智能和弦生成工具-Plugin Boutique Scaler 2 v2.3.1 WiN-MAC
  13. Android设计之UI透明图标
  14. MySQL如何备份整个数据库
  15. 《自来水哲学-松下幸之助自传》读后感
  16. 使用命令行清理Mac 释放磁盘空间
  17. JavaScript为什么成了众多小程序的首选?
  18. 2020 Winter Holiday Schedule
  19. 分享5个黑科技APP,都是优秀好资源,手机里没有的可惜了
  20. 苹果手机更新后开不了机_苹果7突然黑屏,苹果7开不了机

热门文章

  1. python招聘杭州拉勾网_Python3获取拉勾网招聘信息
  2. 作业4—文法和语言总结与梳理
  3. Jenkins - Update information obtained: 不可用 ago;
  4. Module containing this breakpoint has not yet loaded or the breakpoint address not be obtained
  5. 漫谈分布式游戏服务器
  6. 宁德时代钠电池雷声大,雨点小?
  7. Ubuntu16.04 + Titan XP + cuda8.0 + cudnn5.1 + opencv3.3.0 + caffe
  8. 网络字节序与主机字节序的转换 - HEN_MAN的专栏 - 博客频道 - CSDN.NET
  9. 致Play Framework开发者们的一封信
  10. C# worksheet设置Excel样式