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. Nginx Rewrite规则的break和last示例

    break和last各自的作用 官方解释 last:stops processing the current set of ngx_http_rewrite_module directives fol ...

  2. Prism+MaterialDesign+EntityFramework Core+Postgresql WPF开发总结 之 基础篇

    本着每天记录一点成长一点的原则,打算将目前完成的一个WPF项目相关的技术分享出来,供团队学习与总结. 总共分三个部分: 基础篇主要争对C#初学者,巩固C#常用知识点: 中级篇主要争对WPF布局与美化, ...

  3. Web Scraping(网页抓取)基本原理 - 白话篇

    本文主要介绍 Web Scraping 的基本原理,基于Python语言,大白话,面向可爱的小白(^-^). 易混淆的名称: 很多时候,大家会把,在网上获取Data的代码,统称为"爬虫&qu ...

  4. mybatis简单项目

    1,mybatis MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可 ...

  5. MATLAB——nctoolbox安装及使用

    1.nctoolbox安装 nctoolbox是一个Matlab工具箱,它提供对通用数据模型数据集的只读访问. (1)下载nctoolbox安装包. 地址:https://code.google.co ...

  6. 音视频开发-FFmpeg

    音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...

  7. ftp 无法显示远程文件夹

    翻阅了网上前辈们的答案,都未能解决,所以就研究了一下 不需要防火墙的情况,关闭防火墙即可 下面使用的iptables防火墙验证的,其他的请自行验证 研究了好久,发现ftp使用端口波动很大,大概在300 ...

  8. Codeforces Global Round 7

    A. Bad Ugly Numbers 思路 题意: 给我们一个k,让我们用 0-9 之间的数字构成一个 k位数a,a不能被组成a的每一位数字整除. 分析:首先 k等于1,无论我们怎么配都会被整除:当 ...

  9. .net core 实现excel 和 word 的在线预览

    最新在搞文件的在线预览,网上很多免费的方案都需要是电脑安装office的,这要就很麻烦:收费的插件又太贵了. 不过还是找到一款相对好用的免费在线预览插件. 直接在nuget上搜索ce.office.e ...

  10. Go gRPC进阶-超时设置(六)

    前言 gRPC默认的请求的超时时间是很长的,当你没有设置请求超时时间时,所有在运行的请求都占用大量资源且可能运行很长的时间,导致服务资源损耗过高,使得后来的请求响应过慢,甚至会引起整个进程崩溃. 为了 ...