C++运算符重载总结

2023-11-07

一、C++操作符重载的意义

1、当运算符作用于类类型的运算对象时,可以通过运算符重载重新定义该运算符的含义。
2、在模板编程实现的泛型编程中,对不同类型实现相同的语义,各自类通过操作符重载实现对应语义。
例如:由模板类自己定义大小关系。

// FUNCTION TEMPLATE _Min_value
template<class _Ty>
	_Post_equal_to_(_Right < _Left ? _Right : _Left)
	constexpr const _Ty& _Min_value(const _Ty& _Left, const _Ty& _Right)
		_NOEXCEPT_COND(_NOEXCEPT_OPER(_Right < _Left))
	{	// return smaller of _Left and _Right
	return (_Right < _Left ? _Right : _Left);
	}

		// FUNCTION TEMPLATE _Max_value
template<class _Ty>
	_Post_equal_to_(_Left < _Right ? _Right : _Left)
	constexpr const _Ty& _Max_value(const _Ty& _Left, const _Ty& _Right)
		_NOEXCEPT_COND(_NOEXCEPT_OPER(_Left < _Right))
	{	// return larger of _Left and _Right
	return (_Left < _Right ? _Right : _Left);
	}

二、哪些运算符能够重载?哪些不可重载?哪些不该被重载?

1、能够被重载的运算符

//	new delete new[] delete[]	//内存分配的接管作用
//	+ - * / % 
//	^ & | ~ 
//	! = < > 
//	+= -= *= /= %= <= >= 
//	<< >> <<= >>=
//	== != <= >=
//	&& ||
//	++ -- //分前置和后置
//	,
//	->* -> () []				//通过指针取成员指针、通过指针取成员、强制类型转换、数组取下标

2、不可重载的运算符

//	.			通过对象(结构体)取成员
//	.*			通过对象取成员指针
//	::			作用域分辨符
//	?:			条件运算符
//	sizeof		计算数据大小运算符

3、不该被重载的运算符

//	,			//逗号表达式
//	&			//取地址
//	&& ||		//逻辑与逻辑或

三、运算符的重载规则

1、重载后运算符的优先级与结合性不会改变。
2、不能改变原有运算符操作数的个数。
3、不能重载C++没有的运算符。
4、不能改变运算符的原有语义。

四、运算符函数重载的两种形式

1、重载为类的成员函数(隐含参数this)
2、重载为类的非成员函数(一般为友元函数)。

五、什么时候应该重载为类的成员函数运算符,什么时候应该重载为类的友元函数运算符?

1、一般,单目运算符最好重载为类的成员函数,双目运算符则最好重载为友元函数。
2、一些双目运算符(=,(),[],->)不能重载为类的友元函数。
3、类型转换函数只能定义一个类的成员函数。
4、若一个运算符的操作需要修改对象的状态,选择重载成员函数较好。
5、若运算符所需操作数(尤其是第一个操作数)期望有隐式的类型转换,则只能选择友元函数。
6、当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(包括引用)。如果左边操作数必须是一个不同类的对象,或者一个基本数据类型的对象,该运算符必须作为一个友元函数来实现。
7、当需要考虑运算符的运算具有可交互性,选择重载为友元函数。

六、运算符重载实现的示例

Complex.h

#pragma once
#include <iostream>
#include <cmath>

class Complex
{
private:
	double re, im;

public:
	//获取成员变量
	const double& real()const { return re; }
	const double& imag()const { return im; }
	//支持类型转换的构造
	Complex(double r = 0, double i = 0)
		:re(r), im(i)
	{
		std::cout << this << std::endl;
	}
	//拷贝构造
	Complex(const Complex& Com);


	//自我赋值检测的拷贝赋值
	Complex& operator=(const Complex& Com);
	//bool类型转换,在原点为返回false
	explicit operator bool() const noexcept;
	//取反
	Complex operator-() const;
	//前置++,__,实部加1,减法1
	Complex operator++();
	Complex operator--();
	//后置++,__,实部加1,减法1
	Complex operator++(int);					//重点
	Complex operator--(const int);				//const int和int无差别,不能同时存在
	//重载!,求共轭复数
	Complex operator!() const;
	//重载()为仿函数,求模
	double operator()() const;

	//重载<<用以输出复数
	friend std::ostream& operator<<(std::ostream&, const Complex&);
	//加减乘除
	friend Complex operator+(const Complex& Com1, const Complex& Com2);
	friend Complex& operator+=(Complex& Com1, const Complex& Com2);
	friend Complex operator-(const Complex& Com1, const Complex& Com2);
	friend Complex& operator-=(Complex& Com1, const Complex& Com2);
	friend Complex operator*(const Complex& Com1, const Complex& Com2);
	friend Complex& operator*=(Complex& Com1, const Complex& Com2);
	friend Complex operator/(const Complex& Com1, const Complex& Com2);
	friend Complex& operator/=(Complex& Com1, const Complex& Com2);
	//相等、大小判断
	friend bool operator==(const Complex& Com1, const Complex& Com2);
	friend bool operator!=(const Complex& Com1, const Complex& Com2);
	friend bool operator<(const Complex& Com1, const Complex& Com2);
	friend bool operator<=(const Complex& Com1, const Complex& Com2);
	friend bool operator>(const Complex& Com1, const Complex& Com2);
	friend bool operator>=(const Complex& Com1, const Complex& Com2);
};

Complex.cpp

#include "Complex.h"

Complex::Complex(const Complex& Com)
{
	std::cout << this << std::endl;
	this->re = Com.re;
	this->im = Com.im;
}
Complex& Complex::operator=(const Complex& Com)
{
	std::cout << this << std::endl;
	if (this != &Com)
	{
		this->re = Com.re;
		this->im = Com.im;
		return (*this);
	}
	return (*this);
}

Complex::operator bool() const noexcept		//explicit只能写在声明中,不能写在定义中。
{
	if (0 == this->re && 0 == this->im)
		return false;
	else
		return true;
}
Complex Complex::operator-() const
{
	return Complex(-this->re, -this->im);
}
//前置++,--
Complex Complex::operator++()
{
	return Complex(++this->re, this->im);
}
Complex Complex::operator--()
{
	return Complex(--this->re, this->im);
}

//后置++,--
Complex Complex::operator++(int)
//Complex operator++(const int)		//亦可
{
	return Complex(this->re++, this->im);
	//拆分开则为下列三行
	/*Complex Com(*this);
	++this->re;
	return Com;*/
}
Complex Complex::operator--(const int)
{
	return Complex(this->re--, this->im);
}
Complex Complex::operator!() const
{
	return Complex(this->re, -this->im);
}
double Complex::operator()() const
{
	return sqrt(pow(this->re, 2) + pow(this->im, 2));
}

std::ostream& operator<<(std::ostream& os, const Complex& Com)
{
	return os << '(' << Com.real() << ',' << Com.imag() << ')';
}

Complex operator+(const Complex& Com1, const Complex& Com2)
{
	return Complex(Com1.re + Com2.re, Com1.im + Com2.im);
}
Complex& operator+=(Complex& Com1, const Complex& Com2)
{
	Com1.re += Com2.re;
	Com1.im += Com2.im;
	return Com1;
}
Complex operator-(const Complex& Com1, const Complex& Com2)
{
	return Complex(Com1.re - Com2.re, Com1.im - Com2.im);
}
Complex& operator-=(Complex& Com1, const Complex& Com2)
{
	Com1.re -= Com2.re;
	Com1.im -= Com2.im;
	return Com1;
}
Complex operator*(const Complex& Com1, const Complex& Com2)
{
	return Complex((Com1.re * Com2.re) - (Com1.re * Com2.re), (Com1.im * Com2.re) + (Com1.re * Com2.im));
}
Complex& operator*=(Complex& Com1, const Complex& Com2)
{
	Com1.re = (Com1.re * Com2.re) - (Com1.re * Com2.re);
	Com1.im = (Com1.im * Com2.re) + (Com1.re * Com2.im);
	return Com1;
}
Complex operator/(const Complex& Com1, const Complex& Com2)
{
	double acbd = (Com1.re * Com2.re) + (Com1.re * Com2.re);
	double bc_ad = (Com1.im * Com2.re) + (Com1.re * Com2.im);
	double c2d2 = Com2.re * Com2.re + Com2.im * Com2.im;
	return Complex(acbd / c2d2, bc_ad / c2d2);
}
Complex& operator/=(Complex& Com1, const Complex& Com2)
{
	double acbd = (Com1.re * Com2.re) + (Com1.re * Com2.re);
	double bc_ad = (Com1.im * Com2.re) + (Com1.re * Com2.im);
	double c2d2 = Com2.re * Com2.re + Com2.im * Com2.im;
	Com1.re = acbd / c2d2;
	Com1.im = bc_ad / c2d2;
	return Com1;
}

bool operator==(const Complex& Com1, const Complex& Com2)
{
	if (Com1.real() == Com2.real() && Com1.imag() == Com2.imag())
		return true;
	else
		return false;
}
bool operator!=(const Complex& Com1, const Complex& Com2)
{
	if (Com1.real() != Com2.real() || Com1.imag() != Com2.imag())
		return true;
	else
		return false;
}
bool operator<(const Complex& Com1, const Complex& Com2)
{
	if (Com1() < Com2())
		return true;
	else
		return false;

}
bool operator<=(const Complex& Com1, const Complex& Com2)
{
	if (Com1() <= Com2())
		return true;
	else
		return false;
}
bool operator>(const Complex& Com1, const Complex& Com2)
{
	if (Com1() > Com2())
		return true;
	else
		return false;
}
bool operator>=(const Complex& Com1, const Complex& Com2)
{
	if (Com1() >= Com2())
		return true;
	else
		return false;
}

String.h

#pragma once
#include <iostream>
#include <cstring>

class String
{
private:
	char *m_StrData;
public:
	String(const char *strp = nullptr)
	{
		if (nullptr != strp)
		{
			this->m_StrData = new char[strlen(strp) + 1];
			strcpy_s(m_StrData, strlen(strp) + 1, strp);
		}
		else
		{
			this->m_StrData = new char[1];
			*(this->m_StrData) = '\0';
		}
	}
	String(const String& strp)
	{
		this->m_StrData = new char[strp.leng() + 1];
		strcpy_s(this->m_StrData, strp.leng() + 1, strp.m_StrData);
	}
	String& operator= (const String& strp)
	{
		if (this != &strp)
		{
			delete[] m_StrData;
			m_StrData = new char[strp.leng() + 1];
			strcpy_s(this->m_StrData, strp.leng() + 1, strp.m_StrData);
			return (*this);
		}
		return (*this);
	}
	~String()
	{
		if (nullptr != m_StrData)
			delete[] this->m_StrData;
	}

	//字符个数
	unsigned int leng() const
	{
		return strlen(this->m_StrData);
	}

	char& operator[](const unsigned int off)
	{
		return *(m_StrData + off);
	}
	const char& operator[](const unsigned int off) const
	{
		return *(m_StrData + off);
	}
	String* operator->()
	{
		return this;
	}
	const char* operator*() const
	{
		return (this->m_StrData);
	}
	//重载<<
	friend std::ostream& operator<<(std::ostream&, const String&);
};

std::ostream& operator<<(std::ostream& os, const String& strp)
{
	return os << strp.m_StrData;
}

如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++运算符重载总结 的相关文章

随机推荐

  • Xshell突然连接不上虚拟机的解决

    目录 问题描述 失败的尝试 最终解决 感想 问题描述 国庆节后继续学习 在使用Xshell登录虚拟机时突然登不上了 而且只有三台中的一台登不上 考虑到之前对虚拟机的配置是在一台win机器上使用VMware Workstation软件创建了三
  • 锐浪(Grid++Report)报表脚本通过某些字段隐藏控件

    var panduantj Report ParameterByName leix AsString 你的字段名 var xians Report ControlByName chuchai 获取图片控件 if panduantj 出差 x
  • wps合并重复项并求和_表格技巧—Excel中重复项求和的方法

    在Excel统计数据时 经常会碰到重复项反复出现 很干扰视线 想要对重复项进行合并并求和 那要如何操作呢 下面 小编跟大家详细讲解Excel合并重复项数据并求和的操作方法 首先打开一个需要处理的Excel表格 比如对下列表格中相同型号的数量
  • Scrapy中extract_first()和extract()的区别

    测试用到的爬取网站 In 11 print response xpath h3 a title scrapy selector unified SelectorList 是Selector组成的列表 Out 11 为了方便阅读换行符我手打的
  • python降低cpu的占用

    import signal import resource import os import time from multiprocessing import Process def time exceeded signo frame ti
  • 2023华为OD机试真题-工作安排(JAVA、Python、C++)

    题目描述 小明每周上班都会拿到自己的工作清单 工作清单内包含n项工作 每项工作都有对应的耗时时长 单位h 和报酬 工作的总报酬为所有已完成工作的报酬之和 那么请你帮小明安排一下工作 保证小明在指定的工作时间内工作收入最大化 输入描述 输入的
  • Qt 事件过滤器

    通过前面的学习 我们已经知道 Qt 创建了QEvent事件对象之后 会调用QObject的event 函数处理事件的分发 显然 我们可以在event 函数中实现拦截的操作 由于event 函数是 protected 的 因此 需要继承已有类
  • 2023最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)

    近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k 15k的常见面试题 个人录制的最新Vue项目学习视频 B站 Vue2 第二版 后台管理系统项目实战 vue element ui vue经典全套系统案例讲解 哔哩哔哩 bilib
  • python中的 datetime 的使用

    python 中 datetime 的使用方法 介绍 所谓 datetime 其实就是 date time date 和 time的集合 下面介绍使用方法 常搭配logging记录日志 date from datetime import d
  • 三创赛优秀作品_三创赛优秀作品.doc

    PAGE PAGE 138 全国高校首届 创意 创新 创业 电子商务挑战赛 农舍吧 电子商务旅游网站 参赛策划书 北京邮电大学 开心吧 电子商务团队 团队成员 吴新军 林朝波 高有富 陈和磊 指导老师 胡 桃 2009年12月 TOC o
  • Map 和 Set 使用的区别和联系(建议收藏)

    我是目录 1 搜索 1 概念及场景 2 模型 2 Map 的使用 3 Set 的使用 表现 两个接口 Set 和 Map 接口 1 搜索 1 概念及场景 Map 和 set 是一种专门用来进行 搜索的容器 或者 数据结构 其搜索的效率与其具
  • 用递归求斐波那契数列

    2137 斐波那契数列 时间限制 1 Sec 内存限制 128 MB 提交 2116 解决 2242 提交 状态 讨论版 命题人 lym 题目描述 斐波那契数列 Fibonacci sequence 又称黄金分割数列 兔子数列 是数学家列昂
  • MyBatis-Plus:条件构造器Wrapper

    目录 1 Wrapper概述 1 1 Wrapper的继承关系 1 2 Wapper介绍 1 3 各个构造器使用区别 1 4 构造器常用方法 2 Wrapper常用构造器介绍 2 1 QueryWrapper 2 2 UpdateWrapp
  • 无向图的邻接矩阵与邻接表详细实现

    无向图的邻接矩阵 通过用邻接矩阵来表示无向图 如下无向图G1的邻接矩阵 无向图G1包含了 A B C D E F G 共七个顶点 而且包含了 A C A D A F B C C D E G F G 共七条边 由于这是无向图 所以 A C 和
  • Linux命令awk

    文章目录 Linux命令awk 1 搜索 etc passwd文件以root关键字开头的所有行 并输出该行的第7列 2 搜索 etc passwd文件以root关键字开头的所有行 并输出第1列 第6列 第7列 以逗号分隔 3 只显示 etc
  • PPT架构师架构技能图

    PPT架构师架构技能图 目录 概述 需求 设计思路 实现思路分析 1 软素质 2 核心输出 office输出 参考资料和推荐阅读 Survive by day and develop by night talk for import biz
  • 强智教务管理系统爬虫难关1

    强智教务系统的登录页面有个验证码 为了自动化和简单化 采用了联众答题模块 自动识别和验证 下面是我的点数 说明已经可以自动识别验证码并且可以使用了 当然 这个没有什么难度 今天解决的是账号密码加密问题 这个是我抓到的包 很显然 账号密码进行
  • Pyqt5 圆角窗口

    之前了解了通过样式表和绘画的方式 都感觉不太靠谱 样式表无法生效 绘画又会影响定义的其它窗口样式 后来发现还是setMask靠谱 def setMask self args setMask self QBitmap setMask self
  • 大端模式和小端模式

    一 什么是大端 什么是小端 0x123456在内存中的存储方式 大端模式 低地址 gt 高地址 0x12 0x34 0x56 小端模式 低地址 gt 高地址 0x56 0x34 0x12 不难看出大端模式比较符合人的直观认识 二 为什么会有
  • C++运算符重载总结

    一 C 操作符重载的意义 1 当运算符作用于类类型的运算对象时 可以通过运算符重载重新定义该运算符的含义 2 在模板编程实现的泛型编程中 对不同类型实现相同的语义 各自类通过操作符重载实现对应语义 例如 由模板类自己定义大小关系 FUNCT