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

什么是运算符重载

用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载。运算符重载是静态多态性的体现。

运算符重载的规则

  1. 重载公式

返回值类型 operator 运算符名称 (形参表列){}

  1. 能够重载的运算符

    + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new new[] delete delete[]

  2. 不能重载的运算符

    sizeof: ?.::

  3. 重载不能改变运算符的优先级和结合性

  4. 重载不会改变运算符的用法

  5. 运算符重载函数不能有默认的参数

  6. 重载后的运算符必须至少有一个操作数是用户自定义的类型,以此来防止为标准类型重载运算符。

  7. 特殊的运算符

    ->[ ]( )=只能以成员函数的形式重载

运算符重载的实现原理

以运算符作为名称的函数称之为运算符函数。这种重载称为运算符重载。

具体实现(以运算符+ -为例)

1. 在全局范围内重载运算符

Complex operator+(const Complex &leftArg, const Complex &rightArg)
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
Complex sum = leftArg + rightArg;

第五行调用函数operator+,并且将leftArgleftArg作为符号函数的参数,返回值赋值给sum,等同于sum = operator+(leftArg,rightArg);

2.在类中重载运算符

class Complex
{
public:
Complex operator-(const Complex & arg)
{
return Complex(this.real - arg.real, this.imag - arg.imag);
}
};
Complex diff = leftArg - rightArg;

第九行调用函数operator-,并且将leftArg作为符号函数的参数,返回值赋值给diff,等同于diff = leftArg.operator-(rightArg);

运算符重载的使用例子

#include<iostream>
#include<string> using namespace std; enum complePart
{
real = 0,
imag
}; class Complex
{
public:
int real;
int imag;
public:
Complex() : real(0),imag(0){}
Complex(int r, int i) : real(r),imag(i){}
Complex operator-(const Complex & arg)// +,-,*,/ 这四个运算符重载方法一样
{
return Complex(this->real - arg.real, imag - arg.imag);
}
friend Complex operator*(const Complex &leftArg, const Complex &rightArg);//友元函数
bool operator==(const Complex &arg)// ==,!= 这两个个运算符重载方法一样
{
if(this->real == arg.real && this->imag == arg.imag)
return true;
else
return false;
}
Complex& operator+=(const Complex &arg)// +=,-=,*=,/= 这四个运算符重载方法一样
{
this->real += arg.real;
this->imag += arg.imag;
return *this;
}
friend istream& operator>>(istream &input, Complex &complex);
friend ostream& operator<<(ostream &output, Complex &complex);
Complex& operator++()// ++i,--i 这两个个运算符重载方法一样
{
++this->real;
++this->imag;
return *this;
}
Complex operator++(int i)// i++,i-- 这两个个运算符重载方法一样
{
Complex tempComplex = *this;
++this->real;
++this->imag;
return tempComplex;
}
void* operator new(size_t size)
{
cout << "call function void* operator new(size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete(void* pointer)
{
cout << "call function void operator delete(void* pointer)" << endl;
free(pointer);
}
void* operator new[](size_t size)
{
cout << "call function void* operator new[](size_t size)" << endl;
void* pointer = malloc(size);
return pointer;
}
void operator delete[](void* pointer)
{
cout << "call function void operator delete[](void* pointer)" << endl;
free(pointer);
}
void* operator new(size_t size,Complex* complex,int step)//placement new
{
cout << "call function void* operator new(size_t size,Complex* complex,int step)" << endl;
return complex + step;
}
operator int()
{
return this->real;
}//c->operator int()
int& operator [](int i)
{
int errorValue = 0;
if(i == 0)
return this->real;
else//为了演示不要在意
return this->imag;
}
const int& operator[](int i) const
{
cout << "call function const int& operator[](int i) const" << endl;
if(i == 0)
return this->real;
else//为了演示不要在意
return this->imag;
}
}; Complex operator+(const Complex &leftArg, const Complex &rightArg)//全局重载
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
istream& operator>>(istream &input, Complex &complex)
{
input >> complex.real >> complex.imag;
return input;
}
ostream& operator<<(ostream &output, Complex &complex)
{
output << complex.real << " " << complex.imag << " ";
return output;
}
Complex operator*(const Complex &leftArg, const Complex &rightArg)
{
return Complex((leftArg.real * rightArg.real) - (leftArg.imag * rightArg.imag),
(leftArg.imag * rightArg.real) - (leftArg.real * rightArg.imag));
} int main()
{
Complex leftArg(2,2);
Complex rightArg;
cin >> rightArg;//输入3,3
Complex result = leftArg + rightArg;
cout << result << endl;
result = leftArg - rightArg;
cout << result << endl;
result = leftArg * rightArg;
cout << result << endl;
string str = (leftArg == rightArg)?"true":"false";
cout << str << endl;
result += leftArg;
cout << result << endl;
cout << ++result << endl;
Complex resulttttt = result++;
cout << resulttttt << endl;
cout << result << endl;
Complex* pointer = new Complex(1,1);
cout << *pointer << endl;
delete pointer;
Complex* pointerArray = new Complex[10];
cout << pointerArray[2] << endl;
new(pointerArray, 2)Complex(123,321);//placement new
cout << pointerArray[2] << endl;
cout << (int)pointerArray[2] << endl;
cout << pointerArray[2][complePart::real] << endl;
cout << pointerArray[2][complePart::imag] << endl;
delete[] pointerArray;
const Complex c_result(111,222);
cout << c_result[complePart::imag] << endl; return 0;
}
/* 运行结果为:
3 3
5 5
-1 -1
0 0
false
2 2
3 3
3 3
4 4
call function void* operator new(size_t size)
1 1
call function void operator delete(void* pointer)
call function void* operator new[](size_t size)
0 0
call function void* operator new(size_t size,Complex* complex,int step)
123 321
123
123
321
call function void operator delete[](void* pointer)
call function const int& operator[](int i) const
222 --------------------------------
Process exited after 3.063 seconds with return value 0
请按任意键继续. . .
*/

代码分析

1.双目运算符

+-*/%这五个运算符均为双目运算符,重载方法相同。重载例子详见第20、24、102、116行,其中第102行的+重载函数为全局重载,测试详见第127、129、131行。

2.关系运算符

==!=<><=>=这六个运算符均为关系运算符,重载方法相同。重载例子详见第25行,测试详见第133行。

3.自增自减运算符

++--这两个运算符均为自增自减运算符,由于运算符的特殊性,运算符又分为前置和后置形式。重载方法两种形式不同,但是相同形式的重载方法相同。重载例子详见第40、46行,测试详见第137、138行。

4.空间申请与释放运算符

newdeletenew[]delete[]这四个运算符均为空间申请与释放运算符,重载方法相似。重载例子详见第53、59、64、70行,测试详见第141、143、144、151行。在重载空间申请运算符时除newnew[]这两种方式外还有一种方式叫做placement new。重载例子详见第75行,测试详见第146行。

placement new

通常new操作分两步:

  1. 分配内存。
  2. 若为类则调用类的构造函数创建对象。

但是若已分配好内存如:Complex* pointerArray = new Complex[10];,若要在pointerArray[2]分配的内存上创建对象则需要用placement new来完成该操作。操作如下:new(pointerArray, 2)Complex(123,321);,完成该操作后pointerArray[2]中的复数对象将会变为123+321i

5.输入和输出运算符

>><<这两个运算符均为输入和输出运算符,重载方法相似。可以将输出运算符<<和输入运算符>>看作是C++对左移运算符<<和右移运算符>>分别进行了重载,但只能输出输入标准类型。重载例子详见第38、39行,测试详见第126、128行。

6.其它运算符

  1. (数据类型)运算符

    (数据类型)是强制类型转换运算符,可以将对象转换为相应的类型。

  2. []运算符

    []是下标运算符,可以将对象转换为类似数组,可以通过下标操纵对象。

重载运算符的形式

1.以成员函数重载运算符

成员函数重载只允许右参数的隐式转换,一般单目运算符以成员函数重载。只能重载为成员函数的运算符:=()[]->等。

2.以全局函数(友元函数)重载运算符

友元函数重载能够接受左参数和右参数的隐式转换,友员函数重载运算符常用于运算符的左右操作数类型不同的情况。一般双目运算符以友元函数重载。只能重载为友元函数的运算符:<<>>等。

C++基础 学习笔记五:重载之运算符重载的更多相关文章

  1. C#学习笔记_13_静态类&Sealed&运算符重载&抽象类

    13_静态类&Sealed&运算符重载&抽象类 静态类 由static修饰的类就是静态类 特点: 静态类不能实例化对象 静态类中不允许写非静态的成员 静态类只能由一个父类Obj ...

  2. java基础学习笔记五(抽象类)

    java基础学习总结——抽象类 抽象类介绍

  3. Java基础学习笔记(五) - 常用的API

    API介绍 概念:API 即应用编程程序接口.Java API是JDK中提供给我们使用的类说明文档,这些类将底层的代码实现封装.无需关心这些类是如何实现,只需要学习如何使用. 使用:通过API找到需要 ...

  4. Python基础学习笔记(三)运算符

    参考资料: 1. <Python基础教程> 2. http://www.runoob.com/python/python-chinese-encoding.html 3. http://w ...

  5. Java基础学习笔记五 Java基础语法之面向对象

    面向对象 理解什么是面向过程.面向对象 面向过程与面向对象都是我们编程中,编写程序的一种思维方式.面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程.例如:公司打扫卫生( ...

  6. loadrunner基础学习笔记五-场景

    场景目标:模拟10家旅行社同时登录.搜索航班.购买机票.查看航班路线并退出 负载测试是指在典型工作条件下测试应用程序,例如:多家旅行社同时在同一个机票预订系统中预订机票 controller提供所有用 ...

  7. JSP的范围-作用域(web基础学习笔记五)

    JSP的范围(作用域) 在JSP页面中的对象,包括用户创建的对象如JavaBean,都有一个范围属性,这个范围也被叫做“作用域”.范围定义了在什么时间内,在哪一个JSP页面中可以访问这些对象.例如,s ...

  8. Java基础学习笔记总结

    Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...

  9. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

随机推荐

  1. FormDataBodyPart获取表单文件名乱码解决方法

    FormDataMultiPart formData=; FormDataBodyPart filePart=; filePart.getFormDataContentDisposition().ge ...

  2. 不可被忽视的操作系统( FreeRTOS )【2】

    本文章总结基于官方FreeRTOS手册,测试系统为ESP32的IDF 4.0 本篇续上一篇<不可被忽视的操作系统( FreeRTOS )[1]> 其中上一篇主要内容为: FreeRTOS介 ...

  3. eclipse项目导入和导出

    导入导出过程这里推荐一下一篇他人的文章: https://blog.csdn.net/qq_41937388/article/details/87073572 注意: 1.导入第3步中,如果你的项目已 ...

  4. vue引入echart Error in mounted hook: "ReferenceError: myChart is not defined" found in

    解决办法: // 实例化echarts对象 var/let myChart = echarts.init(this.$refs.myChart)

  5. 携程首页--使用flex布局实现

    携程首页 flex解决了float和postion的遗留问题,对移动端比较友好. 需要水平排列的元素就为其父元素设置display:flex,并为子元素添加flex的值(比例) 布局时可以先从大的页面 ...

  6. .NET Core项目部署到Linux(Centos7)(八)为.NET Core项目创建Supervisor进程守护监控

    目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...

  7. 前端面试题解密:经典算法之冒泡算法(ES6版)及优化

    前言 随着前端的飞速发展,前端业务开发给前端工程师提出了更高的要求,因而算法题也越来越高频次的出现在前端面试中.有很多的小伙伴找胡哥苦诉,在前端实际开发中(除了涉及游戏开发方面),算法使用有很多吗?大 ...

  8. php zip打包

    zip中加入文件 <?php $zip = new ZipArchive; if ($zip->open('test.zip', ZipArchive::OVERWRITE) === TR ...

  9. html的嵌套规则

    html元素分为块状元素和内联元素,块状元素作为其他元素的容器. 块状元素可以嵌套其他块状元素 块状元素可以嵌套内联元素 内联元素不能嵌套块状元素 p内不能嵌套块状元素 有几个特殊块状元素只能包含内联 ...

  10. 路由与交换,cisco路由器配置,静态路由

    网络是一个大型的拓扑结构,在路由表中,最重要的是管理距离和度量值 管理距离 管理距离用来确定路由的优先级.管理距离的范围是0-255之间的整数值.值越低代表优先级越高.0代表最高优先级.并且只有直连路 ...