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. Java集合框架要点概括(Core Knowledge of Java Collection)

    目录 有哪些集合类 Set类 Queue类 List类 Map类 HashMap的实现原理,是否线程安全,如何使其做到线程安全 HashMap的实现原理 HashMap的数据结构 HashMap的存取 ...

  2. Springboot 事务注解--- @Transactional

    spring boot @Transactional事物处理    spring boot 添加事物使用 @Transactional注解 简单使用 在启动类上方添加 @EnableTransacti ...

  3. Jenkins打造多分支流水线指南

    overview: 多分支工作流程带来了以下几个关键能力: 在代码仓库中,每个新分支都有自己单独的工作流水线(job). 每个工作流水线都记录了对应分支的构建和变更历史. 可以自定义设置流水线随着分支 ...

  4. 3分钟学会简单使用Vim

    Vim是一款运行在命令行里的文字编辑器,它是Linux人员的标配.在Windows环境下也可以有特别的用处,比如创建没有文件名的文件(.gitignore). Vim的功能十分强大,以至于有一些人对它 ...

  5. 不可思议的hexo,五分钟教你免费搭一个高逼格技术博客

    引言 作为程序员拥有一个属于自己的个人技术博客,绝对是百利无一害的事,不仅方便出门装b,面试时亮出博客地址也会让面试官对你的好感度倍增.经常能在很多大佬的技术文章的文末,看到这样一句话: " ...

  6. ehcahe + redis 实现多级缓存

    1,了解数据存储的位置的不同 数据库:存储在磁盘上 redis:存储在内存上 ehcache:应用内缓存 缓存的目的:是为了将数据从一个较慢的介质上读取出来,放到一个较快的介质上,为了下次读取的时候更 ...

  7. Django-使用 include() 配置 URL

    如果项目非常庞大,应用非常多,应用的 URL 都写在根 urls.py 配置文件中的话,会显的非常杂乱,还会出现名称冲突之类的问题,这样对开发整个项目是非常不利的. 可以这样解决,把每个应用的 URL ...

  8. 操作系统-1-存储管理之LFU页面置换算法(leetcode460)

    LFU缓存 题目:请你为 最不经常使用(LFU)缓存算法设计并实现数据结构.它应该支持以下操作:get 和 put. get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1 ...

  9. c期末笔记(3)

    参数于模运算 1.实参与形参易错点 实参与形参之间是值传递. 实参&形参 实参可以是:常量,表达式或者变量 形参只能是变量 指针和指针变量 1.指针的定义 指针的定义形式:int*p = &a ...

  10. 包格式及IP地址,网络层协议

    包格式及IP地址,网络层协议 案例1:配置静态路由 案例2:配置浮动路由 案例3:配置多路由的静态路由 案例4:配置默认路由 1 案例1:配置静态路由 1.1 问题 配置路由接口IP地址并通过静态路由 ...