C++基础 学习笔记五:重载之运算符重载
C++基础 学习笔记五:重载之运算符重载
什么是运算符重载
用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载。运算符重载是静态多态性的体现。
运算符重载的规则
重载公式
返回值类型 operator 运算符名称 (形参表列){}
能够重载的运算符
+-*/%^&|~!=<>+=-=*=/=%=^=&=|=<<>><<=>>===!=<=>=&&||++--,->*->()[]newnew[]deletedelete[]不能重载的运算符
sizeof、: ?、.、::重载不能改变运算符的优先级和结合性
重载不会改变运算符的用法
运算符重载函数不能有默认的参数
重载后的运算符必须至少有一个操作数是用户自定义的类型,以此来防止为标准类型重载运算符。
特殊的运算符
->、[ ]、( )、=只能以成员函数的形式重载
运算符重载的实现原理
以运算符作为名称的函数称之为运算符函数。这种重载称为运算符重载。
具体实现(以运算符+ -为例)
1. 在全局范围内重载运算符
Complex operator+(const Complex &leftArg, const Complex &rightArg)
{
return Complex(leftArg.real+rightArg.real,leftArg.imag+rightArg.imag);
}
Complex sum = leftArg + rightArg;
第五行调用函数operator+,并且将leftArg、leftArg作为符号函数的参数,返回值赋值给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.空间申请与释放运算符
new、delete、new[]、delete[]这四个运算符均为空间申请与释放运算符,重载方法相似。重载例子详见第53、59、64、70行,测试详见第141、143、144、151行。在重载空间申请运算符时除new、new[]这两种方式外还有一种方式叫做placement new。重载例子详见第75行,测试详见第146行。
placement new
通常new操作分两步:
- 分配内存。
- 若为类则调用类的构造函数创建对象。
但是若已分配好内存如: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.以全局函数(友元函数)重载运算符
友元函数重载能够接受左参数和右参数的隐式转换,友员函数重载运算符常用于运算符的左右操作数类型不同的情况。一般双目运算符以友元函数重载。只能重载为友元函数的运算符:<<、>>等。
C++基础 学习笔记五:重载之运算符重载的更多相关文章
- C#学习笔记_13_静态类&Sealed&运算符重载&抽象类
13_静态类&Sealed&运算符重载&抽象类 静态类 由static修饰的类就是静态类 特点: 静态类不能实例化对象 静态类中不允许写非静态的成员 静态类只能由一个父类Obj ...
- java基础学习笔记五(抽象类)
java基础学习总结——抽象类 抽象类介绍
- Java基础学习笔记(五) - 常用的API
API介绍 概念:API 即应用编程程序接口.Java API是JDK中提供给我们使用的类说明文档,这些类将底层的代码实现封装.无需关心这些类是如何实现,只需要学习如何使用. 使用:通过API找到需要 ...
- Python基础学习笔记(三)运算符
参考资料: 1. <Python基础教程> 2. http://www.runoob.com/python/python-chinese-encoding.html 3. http://w ...
- Java基础学习笔记五 Java基础语法之面向对象
面向对象 理解什么是面向过程.面向对象 面向过程与面向对象都是我们编程中,编写程序的一种思维方式.面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程.例如:公司打扫卫生( ...
- loadrunner基础学习笔记五-场景
场景目标:模拟10家旅行社同时登录.搜索航班.购买机票.查看航班路线并退出 负载测试是指在典型工作条件下测试应用程序,例如:多家旅行社同时在同一个机票预订系统中预订机票 controller提供所有用 ...
- JSP的范围-作用域(web基础学习笔记五)
JSP的范围(作用域) 在JSP页面中的对象,包括用户创建的对象如JavaBean,都有一个范围属性,这个范围也被叫做“作用域”.范围定义了在什么时间内,在哪一个JSP页面中可以访问这些对象.例如,s ...
- Java基础学习笔记总结
Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...
- 尚学堂JAVA基础学习笔记
目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...
随机推荐
- MP3音频文件的剪切合并方法
package com.bytx.ai.service.base.controller.util; import it.sauronsoftware.jave.Encoder;import it.sa ...
- [Java网络安全系列面试题] 说一说TCP和UDP的区别与联系?
TCP TCP是Transfer Control Protocol(传输控制协议)的简称,是一种面向连接的保证可靠传输的协议. 在TCP/IP协议中,IP层主要负责网络主机的定位,数据传输的路由,由I ...
- 分享个Class工具类
import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLCo ...
- Ubuntu下已安装Anaconda但出现conda: command not found错误解决办法
原因:环境未配置 执行[vim ~/.bashrc]命令,进入配置文件,在最后一行按'o'插入一行,并添加语句: export PATH=/home/duanyongchun/anaconda3/bi ...
- [codeforces]Page Numbers <模拟>
描述: «Bersoft» company is working on a new version of its most popular text editor — Bord 2010. Bord, ...
- Java内存模型和ConcurrentHashMap 1.7源码分析
简介 ConcurrentHashMap 是 util.concurrent 包的重要成员.本文将结合 Java 内存模型,分析 JDK 源代码,探索 ConcurrentHashMap 高并发的具体 ...
- 相见恨晚的 Git 命令动画演示,一看就懂!
虽然 Git 是一个强大的工具,但是我觉得大部分人都会同意我说的:它也可以是一个--噩梦!我一直觉得,使用 Git 的时候把操作过程在脑海里视觉化会非常有用:当我执行某个命令的时候,分支之间是如何交互 ...
- Chrome截图截满滑动栏,QQ截长屏,录屏
1.Chrome截图截满滑动栏 一般我们截图都是用QQ的Ctrl+shift+A,但是网页不好截,这里我们可以用Chrome控制台来截全网页: F12或Ctrl+shift+i打开控制台: 点击一下控 ...
- Linux 定时实行一次任务命令
当我们想在指定的时间自动执行 一次 任务的时候,可以使用at命令 启动服务 使用时首先检查atq的服务是否启动 service atd status # 检查atd的状态 service atd st ...
- golang+docker 进入镜像测试本地通信
首先进入docker镜像: docker-compose exec 镜像 sh //进入镜像 然后添加curl命令 apk add curl 最后在使用 curl -d localhost:809 ...