C++之运算符重载

2023-11-06

目录

1.运算符重载:1.可实现的对象

​编辑2.定义运算符重载函数的一般格式: 

3.运算符的重载实际

2.为什么要重载?

 3.前提:

4.如何重载?

5.默认

6.指针作为数据成员

7.字符串重载

8.友元重载:重载输出<<运算符 

9.运算符重载函数的总结

10.重载运算符有以下几种限制


1.运算符重载:
1.可实现的对象

--让类类型的对象像基本数据类型一样去操作,例如,可以实现对象+,-,*,/,%,==,! = [] () << >>等


2.定义运算符重载函数的一般格式: 

返回类型 operator 运算符(参数列表) 比如:operator=(const A&str)

返回值类型 类名::operator重载的运算符(参数表){……}
operator是关键字,它与重载的运算符一起构成函数名。因函数名的特殊性,C++编译器可以将这
类函数识别出来。

3.运算符的重载实际

是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该重载的运算符时调用此函数。这个函数叫做运算符重载函数,通常为类的成员函数。

2.为什么要重载?

如何实现两个同类的对象相加?

class A
{
public:
	A(int i=0):m_i(i){}
private:
	int m_i;
};
void main()
{
	A a(5), b(7);
	cout<<a+b<<endl;
}

 我们发现两个A类对象并不能直接相加。

class A
{
public:
	A(int i=0):m_i(i){}
private:
	int m_i;
};

class STR
{
public:
	STR(const char* str = "\0")
	{
		m_str = new char[strlen(str) + 1];
		strcpy_s(m_str, strlen(str) + 1, str);
	}
private:
	char* m_str;
};

void main()
{
	A a(5), b(7);
	//cout<<a+b<<endl;//两个A类的对象,不能直接相加
	int aa = 5, bb = 7;
	cout << aa + bb << endl;

	STR s("1234567");
	string str = "123456";
	string s1 = "123", s2 = "456";
	string s3 = s1 + s2;
	cout << str << endl;
	str[3] = 'k';
	cout << str << endl;
	cout << "s3= " << s3 << endl;
	//s[2] = 'k';
}

我们发现如果将我们写的类的内容,直接写为int这一大类的内容相加的时候是可以实现的,于是我们可以通过之前的接口,将A类的i直接获得,变为两个int类的相加

 

class A
{
public:
	A(int i = 0,int j=0) :m_i(i),m_j(j) 
	{

	}
	const int& GetI()const
	{

		return m_i;
	}
	const int& GetJ()const
	{
		return m_j;
	}
	A ADD(const A& b)
	{
		return A(m_i+b.m_i,m_j+b.m_j);
	}
	void Print()
	{
		cout << m_i << " " << m_j << endl;
	}
private:
	int m_i;
	int m_j;
};

void main()
{
	A a(5), b(7);
	//cout<<a+b<<endl;
	//cout << a.m_i + b.m_i << endl;//error//本质上就是把对象的数据成员进行相加
	cout << a.GetI() + b.GetI() << endl;
	cout << a.GetJ() + b.GetJ() << endl;
	a.ADD(b).Print();
}

看起来不直观,可读性低

并且当类的成员越来越多时,这样显得非常麻烦

 3.前提:

void main()
{
	int a = 10, b = 3;
	int c = 0;
	c = a + b;
	//a+b=c;//error
	++a = c;
	//b++=13;//error
	cout << a << endl;
	(a = b) = c;
}

1.c = a + b;//从a的内存空间把a的值取出来,从b的内存空间把b的值取出来,把相加过的值放在c的空间

2.a+b=c;//error//从c的内存空间把c的值取出来,a+b(的空间是临时空间,表达式结束,空间就释放了)没有确定的(永久)空间存放c
3.++a = c;//(现在的a=11=执行过表达式后的a的值)将c放到a的存储单元
4.//b++=13;//error//(b=3,b++=4,值不一样,b++没有确定空间)

4.如何重载?

class A
{
public:
	A(int i=0):m_i(i)//构造函数可作为类型转换
	{

	}
	void Print()
	{
		cout << m_i << endl;
	}
	A operator+(const A&b)//本质是实现对象的数据成员的加法
	{
		return m_i + b.m_i;
	}
	//A operator-(const A& a)//b-a b.operator-(a)本质是实现对象的数据成员的减法
	//{
	//	return this->m_i - a.m_i;
	//}
	A operator-(const A& s)//b-a b.operator-(a)本质是实现对象的数据成员的减法
	{
		return this->m_i - s.m_i;
	}
	A& operator++()//++a a.++
	{
		++m_i;//将a自己的数据成员进行修改
		return *this;//修改完后,返回自己本身
	}
	/*
	* b++,表达式的值是,b没加的值,执行完成后,b+1,所有在重载之后++,得体现两种值
	*/
	A operator++(int)//int 没有实际性作用,只是为了区分前置++
	{
		int t = m_i;//保存自己
		m_i = m_i + 1;//+1
		return t;//返回没加以前保存的值
		//return m_i++//等价与上面三句话
	}
private:
	int m_i;
};

int main()
{
	A a(2), b(6);
	(a + b).Print();
	(b - a).Print();
	(a - b).Print();
	(++a).Print();
	(b++).Print();
	b.Print();

}

    (a + b).Print();//a.+(b)//成员形式//(a,b)//友元
    (b - a).Print();//b.-(a);
    (a - b).Print();//a.-(b)
    (++a).Print();//3
    (b++).Print();//b加之前//6
    b.Print();//上式+1 7

5.默认

如果程序员没有提供赋值运算符,则类会提供一个默认的,默认的功能为:
         用右边的对象的数据成员依次给左边对象的数据成员赋值

class A
{
public:
	A(int i = 0, int j = 0) :m_i(i), m_j(j)
	{
	}
	void Print()
	{
		cout << m_i << " " << m_j << endl;
	}
private:
	int m_i;
	int m_j;
};

void main()
{
	A a(2, 6);
	A b;
	a.Print();
	b.Print();
	b = a;
	b.Print();
}

   

    a.Print();// 2 6
    b.Print();// 0 0
    b = a;// 2 6用a的值重新给b赋值,调用了默认的赋值运算符重载函数
    b.Print();

6.指针作为数据成员

class Person
{
public:
	Person(const char*name="\0")
	{
		m_name = new char[strlen(name) + 1];
		strcpy_s(m_name, strlen(name) + 1, name);
	}
	void Print()
	{
		cout << m_name << endl;
	}
	~Person()
	{
		delete[]m_name;
		m_name = NULL;
	}
	Person& operator=(const Person& s)//析构+拷贝构造
	{
		if (this == &s)//判断自赋值
			return *this;
		delete[]m_name;
		m_name = new char[strlen(s.m_name) + 1];
		strcpy_s(m_name, strlen(s.m_name) + 1, s.m_name);

		return *this;
	}
private:
	char* m_name;
};

void main()
{
	Person p1("lisi");
	Person p2("11");
	p1.Print();
	p2.Print();
	p2 = p1;  
	p2.Print();
}

总结:

如果有指针作为数据成员,则赋值运算符重载也要写出来,让两个而不同的对象的指针分别指向内存单元,不过里面的内容保持相同
* 赋值=能作为左值,所以引用返回

if (this == &s) //判断自赋值
            return *this;
        //先将左边对象原本的内存空间释放掉
        delete[]m_name;
        //接着开辟和右边对象s相同大小的内存单元
        m_name = new char[strlen(s.m_name) + 1];
        strcpy_s(m_name, strlen(s.m_name) + 1, s.m_name);

p2 = p1;  //用p1给p2重新赋值,如果调用默认的赋值重载,则让p2的指针重新指向了p1的指针,p1和p2的指针指向同一块空间,但是p2原本的空间还在

7.字符串重载

class STR
{
public:
	STR(const char* str = "\0")
	{
		m_str = new char[strlen(str) + 1];
		strcpy_s(m_str, strlen(str) + 1, str);
	}
	STR(const STR& s)
	{
		m_str = new char[strlen(s.m_str) + 1];
		strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);
	}
	~STR()
	{
		cout << "~STR " << m_str << endl;
		if (m_str != NULL)
		{
			delete[]m_str;
			m_str = NULL;
		}
	}
	STR operator+(const STR& s)//a+b 其实就是将两个对象中的字符串合并
	{
		char* temp = new char[strlen(m_str) + strlen(s.m_str) + 1];
		strcpy_s(temp, strlen(m_str)+1, m_str);
		strcat_s(temp,strlen(m_str)+strlen(s.m_str)+1, s.m_str);
		STR ss(temp);
		delete[]temp;
		temp = NULL;
		return ss;
	}
	STR& operator=(const STR& s)
	{
		if (this == &s)
			return *this;
		delete[]m_str;
		m_str = new char[strlen(s.m_str) + 1];
		strcpy_s(m_str, strlen(s.m_str) + 1, s.m_str);
		return *this;
	}
	void Print()
	{
		cout << "m_str = "<<m_str << endl;
	}
	char& operator[](int index)
	{
		if (index >= 0 && index < strlen(m_str)) //"1234"
			return m_str[index];
	}
	int operator==(const STR& s)
	{
		return strcmp(m_str, s.m_str)==0;
	}
private:
	char* m_str;
};
void main()
{
	STR a("111"), b("222");
	cout << "a:" << endl;
	a.Print();
	cout << "b:" << endl;
	b.Print();
	STR c = a + b;//拷贝构造 111222
	cout << "c:" << endl;
	c.Print();//111222
	STR d;
	d = c;//赋值=运算符重载
	cout << "d:" << endl;
	d.Print();//111222
	c[5] = 'h';
	cout << "c[5]" << endl;
	cout << c[5] << endl;//11122h
	cout << "c:" << endl;
	c.Print();
	cout << "a==b" << endl;
	cout << (a == b) << endl;//0
	cout << "a!=b" << endl;
	cout << (a != b) << endl;//1
}

8.友元重载:重载输出<<运算符 

cout--ostream类的对象
cin--istream类的对象
cout << a;
一般情况下运算符可以解析成下面两种形式
1.cout.<<(a)   ostream类中重载了<<,程序员不能修改
2.<<(cout,a)   可以在程序员自己定义的类中将<<重载成友元
cout<<a<<b; 
cout<<a这个表达式作为了上面的表达式<<左边 返回值为引用
(cout<<a) << b 表达式执行完后,还能继续用<<,说明返回值为ostream类型

friend ostream& operator<<(ostream &out,A &a)

class Magic
{
	double x;
public:
	Magic(double d=0.00):x(fabs(d)){}
	Magic operator+(Magic c)
	{
		return Magic(sqrt(x * x + c.x * c.x));
	}
	friend ostream& operator	<< (ostream& os, Magic c);
};
ostream& operator	<< (ostream& os, Magic c)
{
	return os << c.x;
}
void main()
{
	Magic ma;
	cout << ma << ',' << Magic(-8) << "," << ma + Magic(-3) + Magic(-4);
}

9.运算符重载函数的总结

1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右 操作数作为函数的实参。

2、当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个 或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函 数,而右操作数是该函数的参数。

3、单目运算符“++”和“--”存在前置与后置问题。 前置“++”格式为: 返回类型 类名::operator++(){……} 而后置“++”格式为: 返回类型 类名::operator++(int){……} 后置“++”中的参数int仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。

4、C++中只有极少数的运算符不允许重载。

还有 # , ## , // , / * */ 

10.重载运算符有以下几种限制

不可臆造新的运算符.

不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数.

运算符重载不宜使用过多.

重载运算符含义必须清楚,不能有二义性

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

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

随机推荐

  • 美团团购订单系统优化记

    美团团购订单系统优化记 团购订单系统简介 美团团购订单系统主要作用是支撑美团的团购业务 为上亿美团用户购买 消费提供服务保障 2015年初时 日订单量约400万 500万 同年七夕订单量达到800万 目标 作为线上S级服务 稳定性的提升是我
  • websocketpp的使用和boost库的交叉编译

    最近使用嵌入编程时需要使用websocket 在github上查找开源库时 主要有两个库点赞比较高的 其中一个是websocketpp这个库 此库需要使用boost库进行编译 所以本文章主要介绍boost库的交叉编译和在程序中使用webso
  • wesome-android

    awesome android Introduction android libs from github System requirements Android Notice If the lib is no longer being m
  • MFC使控件失去焦点的方法

    转自 http newthnote blogbus com logs 67403982 html 1 SetFocus另外一个控件 GetDlgItem 另一个控件名 gt SetFocus 2 给要失去焦点的控件发WM KILLFOCUS
  • 使用Spring Security的多租户应用程序的无状态会话

    从前 我发表了一篇文章 解释了构建无状态会话的原理 巧合的是 我们再次针对多租户应用程序执行同一任务 这次 我们将解决方案集成到Spring Security框架中 而不是自己构建身份验证机制 本文将解释我们的方法和实现 业务需求 我们需要
  • 联想原生系统恢复工具F11 安装方法

    因为种种原因 联想笔记本或电脑被二次格式化分区重装系统 导致丢失原生恢复系统恢复工具 F11 即菜单启动F11变成了F12按钮 即原正版授权变成了盗版系统 想恢复原生系统 官方其实提供了方法 联想USB Recovery Creator是一
  • 判断一个点是否在矩形内部

    判断一个点是否在矩形内部 题目描述 在二维坐标系中 所有的值是double类型 那么一个矩形可以由四个点来代表 x1 y1 为最左的点 x2 y2 为最上的点 x3 y3 为最下的点 x4 y4 为最右的点 给定4个点代表的矩形 再给定一个
  • Istio的安装与部署

    安装步骤 准备Kubernetes环境 下载Istio 安装Istio 准备Kubernetes环境 根据Istio官网给出的信息 当前最新的Istio1 5支持以下多种平台的Kubernetes环境 1 14 1 16 我本地安装的是do
  • tf.nn.dynamic_rnn和tf.nn.static_rnn

    文章目录 一 tf nn dynamic rnn 1 函数定义 2 参数说明 3 代码实例 二 tf nn static rnn 1 函数定义 2 参数说明 3 代码实例 补充说明 outputs和state有什么关系 一 tf nn dy
  • C#和.NET基础知识——学习笔记(三)

    面向对象的概念 1 类和对象 类是模子 确定对象将会拥有的特征 属性 和行为 方法 类是对象的类型 类是抽象的概念 对象可以叫做类的实例 Instance 语法 访问修饰符 class 类名 成员 访问修饰符 C 中有4个访问修饰符 pub
  • 什么是mock数据、mock数据使用步骤

    mock这词本意是虚拟 模拟的意思 mock server工具 通俗来说 就是模拟服务端接口数据 一般用在前后端分离后 前端人员可以不依赖API开发 而在本地搭建一个JSON服务 自己产生测试数据 即 json server就是个存储jso
  • java中request接收数组(即request接收多个同名参数)

    例如 复选框 勾选多个内容的时候 提交
  • 四层负载均衡和七层负载均衡的区别

    四层负载均衡和七层负载均衡的区别 1 四层负责均衡 是通过报文中的目标地址和端口 再加上负载均衡设备设置的服务器选择方式 决定最终选择的内部服务器与请求客户端建立TCP连接 然后发送Client请求的数据 由上图可知 在四层负载设备中 把c
  • 微信小程序——云函数

    云函数是一种在小程序端编写 定义 通过开发工具部署到云服务器中 在小程序端可以远程调用的函数 这种函数在云服务器中执行 所以云函数可以简单替代nodejs后端接口 体验云函数 1 创建云函数 前提 在新建项目时 选择 云开发 找到当前文件夹
  • 使用vantUI

    https www jb51 net article 147333 htm
  • Linux c/c++之文件拷贝

    Linux c c 之文件拷贝 命令方式进行文件拷贝 直接使用system 函数通过命令的方式拷贝文件 cp 路径 旧文件名 路径 新文件名 文件拷贝 直接使用命令方式拷贝 include
  • YOLOv5车辆测距实践:利用目标检测技术实现车辆距离估算

    YOLOv5目标检测技术进行车辆测距 相信大家对YOLOv5已经有所了解 它是一种快速且准确的目标检测算法 接下来 让我们一起探讨如何通过YOLOv5实现车辆距离估算 这次的实践将分为以下几个步骤 安装所需库和工具 数据准备 模型训练 距离
  • nginx: [emerg] BIO_new_file("/etc/nginx/ssl_key/server.crt") failed (SSL: error:02001002:syste

    Centos 7 5 nginx web集群配置https报错 报错信息 root lb01 conf d nginx tnginx emerg BIO new file etc nginx ssl key server crt faile
  • c++基础练习题五

    1 编程实现以下功能 具体要求如下 1 设计一个汽车类vehicle 包含的数据成员有车轮个数wheels和车重weight 有相关数据的输出方法 2 小车car是它的派生类 其中包含载人数passenger load 有相关数据的输出方法
  • C++之运算符重载

    目录 1 运算符重载 1 可实现的对象 编辑2 定义运算符重载函数的一般格式 3 运算符的重载实际 2 为什么要重载 3 前提 4 如何重载 5 默认 6 指针作为数据成员 7 字符串重载 8 友元重载 重载输出 lt lt 运算符 9 运