C++ :运算符重载

news2024/11/22 14:20:03

运算符重载:

运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

 

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

定义运算符重载函数的一般格式
返回值类型 类名::operator重载的运算符(参数表)  {.......}

operator是关键字,它与重载的运算符一起构成函数名。因函数名的特殊性,C++编译器可以将这类函数识别出来

加号运算符重载: 

作用:实现两个自定义数据类型相加的运算

1.成员函数实现 + 号运算符重载

 

#include <iostream>
using namespace std;

//加号运算符重载

class Person
{
public:

    //1 成员函数实现 + 号运算符重载
    Person operator+(Person& p)
    {
        Person temp;
        temp.m_A = this->m_A + p.m_A;
        temp.m_B = this->m_B + p.m_B;
        return temp;
    }

    int m_A;
    int m_B;
};

void test01() {
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;
    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

    Person p3 = p1 + p2;

    cout <<  "p3.m_A = " << p3.m_A<< endl;
    cout <<  "p3.m_B = " << p3.m_B<< endl;
}

int main() {
    test01();

    system("pause");
    return 0;
}

(2).全局函数重载:

class Person
{
public:

    //1 成员函数实现 + 号运算符重载
    /*Person operator+(Person& p)
    {
        Person temp;
        temp.m_A = this->m_A + p.m_A;
        temp.m_B = this->m_B + p.m_B;
        return temp;
    }*/

    int m_A;
    int m_B;
};

//2.全局函数重载+号
Person operator+(Person& p1, const Person& p2)
{
    Person temp;
    temp.m_A = p1.m_A + p2.m_A;
    temp.m_B = p1.m_B + p2.m_B;
    return temp;
}

//3 运算符重载 可以发生函数重载
Person operator+(Person& p1, int num)
{
    Person temp;
    temp.m_A = p1.m_A + num;
    temp.m_B = p1.m_B + num;
    return temp;
}

void test01() {
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;
    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;


    //成员函数方式
    Person p3 = p2 + p1; //相当于 p2.operaor+(p1)
    Person p3 = p1 + p2;


    //全局函数重载本质调用:
    Person p3 = operator+(p1, p2);
    Person p3 = p1 + p2;

    //

    cout <<  "p3.m_A = " << p3.m_A<< endl;
    cout <<  "p3.m_B = " << p3.m_B<< endl;
}



int main() 
{
    test01();

    system("pause");
    return 0;
}

2.左移运算符重载

作用:可以输出自定义数据类型
#include <iostream>
using namespace std;

//左移运算符重载

class Person
{
    friend ostream& operator<<(ostream& cout, Person& p);

public:
    Person(int a, int b)
    {
        this->m_A = a;
        this->m_B = b;
    }
private:
//成员函数 实现不了  p << cout 不是我们想要的效果
 //void operator<<(Person& p){
 //}
    int m_A;
    int m_B;
};

//全局函数实现左移重载
ostream& operator<<(ostream& cout, Person &p)  //本质 operator<<(cout,p) 简化cout<<p
{
    cout << "m_A = " << p.m_A << " m_B = " << p.m_B;
    return cout;
}


void test01()  
{
    Person p(10,10);
    //p.m_A = 10;
    //p.m_B = 10;

    cout << p<<"hello world"<<endl; //链式编程   输出一个对象就能打印他的属性
} 


int main() 
{
    test01();

    system("pause");
    return 0;
}

总结:重载左移运算符配合友元可以实现输出自定义数据类型

3.递增运算符重载

作用: 通过重载递增运算符,实现自己的整型数据
总结:前置递增返回引用,后置递增返回值
先写一个输出整形数据的:

class MyInteger 
{
    friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
    MyInteger() {
        m_Num = 0;
    }



private:
    int m_Num;
};

//重载左移运算符
ostream& operator<<(ostream& cout, MyInteger myint)
{
    cout << myint.m_Num << endl;    //全局函数想要访问私有属性
    return cout;
}
void test01()
{
    MyInteger myint;
    cout << myint << endl;
    

}


int main() 
{
    test01();

    system("pause");
    return 0;
}

输出结果: 0

 

class MyInteger 
{
    friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
    MyInteger() {
        m_Num = 0;
    }
    //重载前置++运算符 返回引用为了一直对一个数据进行递增操作
   MyInteger& operator++()
    {
       //先++
        m_Num++;
        //再返回
        return *this;
    }
    //重载后置++运算符  
    //int代表占位参数,可以用于区分前置和后置递增
   MyInteger operator++(int)
   {
      //先记录当时结果
       MyInteger temp = *this;
       //后递增
       m_Num++;
       //最后将记录结果做返回
       return temp;
   }

private:
    int m_Num;
};

//重载左移运算符
ostream& operator<<(ostream& cout, MyInteger myint)
{
    cout << myint.m_Num << endl;    //全局函数想要访问私有属性
    return cout;
}
void test01()
{
    MyInteger myint;

    cout << ++myint << endl;
 
}

void test02()
{
    MyInteger myint;
    cout << myint++ << endl;
    cout << myint << endl;
}


int main() 
{
   // test01();
    test02();
    system("pause");
    return 0;
}

4.赋值运算符重载: 

c++ 编译器至少给一个类添加 4 个函数
1. 默认构造函数 ( 无参,函数体为空 )
2. 默认析构函数 ( 无参,函数体为空 )
3. 默认拷贝构造函数,对属性进行值拷贝
4. 赋值运算符 operator=, 对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
class Person
{
public:
	Person(int age)
	{
		m_Age = new int(age);  //把数据创建在堆区 
	}
	~Person()
	{
		if (m_Age != NULL)
		{
			delete m_Age;
			m_Age = NULL;
		}
	}                           //释放堆区内存  

	int* m_Age;



};

void test01()
{
	Person p1(18);
	Person p2(20);
	p2 = p1;    //赋值操作

	cout << "p1的年龄为:" << *p1.m_Age << endl;
	cout << "p2的年龄为:" << *p2.m_Age << endl;
}


int main()
{
	test01();

	system("pause");
	return 0;
}

上示代码会崩;

 崩溃原因:堆区内存重复释放

 

解决方法: 

 示例如下:

class Person
{
public:
	Person(int age)
	{
		m_Age = new int(age);  //把数据创建在堆区 
	}
	~Person()
	{
		if (m_Age != NULL)
		{
			delete m_Age;
			m_Age = NULL;
		}
	}                           //释放堆区内存  
	 
	//重载 赋值运算符    (编译器默认提供) 是一个浅拷贝的操作,创建在堆区d的属性,就会出现堆区内存重复释放
	Person& operator=(Person &p)  //返回引用
	{
		//编译器提供的代码是浅拷贝
        //m_Age = p.m_Age;

		//应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
		if (m_Age != NULL)
		{
			delete m_Age;
			m_Age = NULL;
		}
		//提供深拷贝 解决浅拷贝的问题

		m_Age = new int(*p.m_Age);

		//返回自身  为了实现连等
		return *this;
	}


	int* m_Age;        //创建在堆区

};

void test01()
{
	Person p1(18);
	Person p2(20);
	Person p3(30);
	p3 = p2 = p1; //赋值操作

	cout << "p1的年龄为:" << *p1.m_Age << endl;
	cout << "p2的年龄为:" << *p2.m_Age << endl;
	cout << "p3的年龄为:" << *p3.m_Age << endl;

}


int main()
{
	test01();


	system("pause");
	return 0;
}

拷贝构造函数 与赋值重载函数的区别。
总结: 浅赋值与深复制。
什么时候使用深拷贝和深赋值。
在类型设计中,使用动态内存或使用内核对象时,必须重新实现拷贝构造函数和赋值重载 

 5.关系运算符重载:

作用: 重载关系运算符,可以让两个自定义类型对象进行对比操作
如下图,对于内置类型来说,编译器可以正常运行,但是对于自定义类型来说,程序会出现崩溃现象。
class Person
{
public:
	Person(string name, int age)   //用构造函数进行赋初值
	{
		m_Name = name;
		m_Age = age;
	}

	string m_Name;
	int m_Age;


};

void test01()
{
	Person p1("Tom", 18);
	Person p2("Tom", 18);

	if (p1 == p2)  、//err
	{
		cout << "a和b相等" << endl;
	}
	else
	{
		cout << "a和b不相等" << endl;
	}
}

int main()
{
	test01();

	system("pause");
	return 0;
}

对于== 

重载关系运算符,可以让两个自定义类型对象进行对比操作 

class Person
{
public:
	Person(string name, int age)   //用构造函数进行赋初值
	{
		m_Name = name;
		m_Age = age;
	}
	//重载 == 号
	bool operator==(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	string m_Name;
	int m_Age;


};

void test01()
{
	Person p1("Tom", 18);
	Person p2("Tom", 18);

	if (p1 == p2)   //err 需要重载==
	{
		cout << "p1和p2相等" << endl;
	}
	else
	{
		cout << "p1和p2不相等" << endl;
	}
}

int main()
{
	test01();

	system("pause");
	return 0;
}

 对于!= 

class Person
{
public:
	Person(string name, int age)   //用构造函数进行赋初值
	{
		m_Name = name;
		m_Age = age;
	}
	//重载 == 号
	bool operator==(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	bool operator!=(Person& p)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return false;
		}
		else
		{
			return true;
		}
	}


	string m_Name;
	int m_Age;


};

void test01()
{
	Person p1("Tom", 18);
	Person p2("Jerry", 18);

	if (p1 == p2)   //err 需要重载==
	{
		cout << "p1和p2相等" << endl;
	}
	else
	{
		cout << "p1和p2不相等" << endl;
	}

	if (p1 != p2)   //err 需要重载==
	{
		cout << "p1和p2是不相等" << endl;
	}
	else
	{
		cout << "p1和p2相等" << endl;
	}
}

int main()
{
	test01();

	system("pause");
	return 0;
}


运行结果:

 

6.函数调用运算符重载

函数调用运算符 () 也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活
//打印输出类
class MyPrint
{
public:
	//重载函数调用运算符 也称为仿函数
	void operator()(string test)  //()代表了函数名 (string test) 形参列表
	{
		cout << test << endl;
	}
};

void MyPrint02(string test)
{
	cout << test << endl;
}

void test01()
{
	MyPrint myPrint;
	myPrint("hello world");//由于使用起来非常类似于函数调用,因此称为仿函数
	MyPrint02("hello world");      //函数调用
}

//仿函数非常灵活 没有固定的写法  依照需求 写对应的仿函数
//加法类

class MyAdd  //实现两数相加
{
public:
	int operator()(int num1,int num2)
	{
		return num1 + num2;
	}
};

void test02()
{
	MyAdd myadd;   //先创建对象
	int ret = myadd(100, 100);
	cout << "ret = " << ret << endl;

	//匿名对象调用  类型加小括号
	cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}



int main() 
{
	test01();
	//test02();
	system("pause");
	return 0;
}

运算符重载函数的总结:


1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右操作数作为函数的实参。
2、当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。
3、单目运算符“++”和“"存在前置与后置问题.

前置“++"格式为:
返回类型 类名::operator++(){......}
而后置“++"格式为:
返回类型 类名::operator++(int){......}
后置“++”中的参数int仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。

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

重载运算符有以下几种限制:
不可臆造新的运算符.
不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数.
运算符重载不宜使用过多
重载运算符含义必须清楚,不能有二义性 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1274039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日一练2023.11.30——验证身份【PTA】

题目链接 &#xff1a;验证身份 题目要求&#xff1a; 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&a…

万界星空科技/仓库管理WMS系统/免费仓库管理系统

仓库管理&#xff08;仓储管理&#xff09;&#xff0c;指对仓库及仓库内部的物资进行收发、结存等有效控制和管理&#xff0c;确保仓储货物的完好无损&#xff0c;保证生产经营活动的正常进行&#xff0c;在此基础上对货物进行分类记录&#xff0c;通过报表分析展示仓库状态、…

HarmonyOS4.0 ArkUI组件

目录 简介 搭建开发环境 ArkUI基础组件 Image组件 Text组件 TextInput Button Slider 简介 HarmonyOS 4.0的ArkUI组件是一套UI开发框架&#xff0c;提供开发者进行应用UI开发时所必须的能力。在ArkUI中&#xff0c;组件是界面搭建与显示的最小单位&#xff0c;开发者通过…

传统算法:使用 Pygame 实现线性查找

使用 Pygame 模块实现了线性查找的动画演示。首先,它生成一个包含随机整数的数组,并通过 Pygame 在屏幕上绘制这个数组的条形图。接着,通过线性查找算法对数组进行查找,动画效果可视化每一步的变化。在查找的过程中,程序逐个遍历数组元素,如果找到目标值,将相应的元素高…

java-Swing界面简析

一、简析&#xff1a; 调用java提供的 java.swing包下的各种类可以实现界面中的各种组件(比如输入框、密码框按钮、单选框、复选框等) 二、java.swing包的关键类&#xff1a; 顶层容器&#xff1a;Jframe(窗口) 中间容器&#xff1a;Jpanel(面板) 基本控件&#xff1a; I…

java开发之个微群聊自动添加好友

请求URL&#xff1a; http://域名/addRoomMemberFriend 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是String登录实例标识chatRoom…

【数据分析 | Numpy】Numpy模块系列指南(一),从设计架构说起

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

Springboot快速整合kafka

kafka的基本了解 kafka也是 目前常用的消息中间件,支持同步与异步通信,和rabbitmq一样,工作模式大概相同,并且被spingboot整合的后的都是 中间件Template的实列化客户端类 ,消费者监听注解为KafkaListener,和RabbitListener和很相似,这些消息中间件使用过后,发现大致都是相同的…

【Node.js】解决npm报错:RequestError: unable to verify the first certificate

1. 问题简述 帖主从nodejs官网下载安装nodejs后&#xff0c;发现使用以下命令安装electron会报错&#xff1a; npm install electron 报错信息如下&#xff1a; npm ERR! RequestError: unable to verify the first certificate 2. 解决方案 网上列举的方案&#xff0c;无…

【刷题笔记】串联所有单词的子串||暴力通过||滑动窗口

串联所有单词的子串 1 题目描述 https://leetcode.cn/problems/substring-with-concatenation-of-all-words/ 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 …

PGSQL(PostgreSQL)数据库安装教程

安装包下载 下载地址 下载后点击exe安装包 设置的data存储路径 设置密码 设置端口 安装完毕&#xff0c;配置PGSQL的ip远程连接&#xff0c;pg_hba.conf&#xff0c;postgresql.conf&#xff0c;需要更改这两个文件 pg_hba.conf 最后增加一行 host all all …

如何计算数据泄露的成本

现在&#xff0c;几乎所有类型的组织每天都在发生企业 IT 网络遭到破坏的情况。它们是任何合规官员最担心的问题&#xff0c;并且找出更好的方法来防止它们或从中恢复是合规官员永远不会远离的想法。 但数据泄露的实际成本是多少&#xff1f;该数字从何而来&#xff1f;当您获…

手动将jar包导入本地Maven仓库

1、进入存放jar包的目录&#xff0c;可以先放进仓库底下 2、cmd回车 3、执行命令&#xff0c;看到BUILD SUCCESS就是成功了 -DgroupId、-DartifactId、-Dversion、-Dfile记得换成自己对应的 mvn install:install-file -DgroupIdcom.github.03 -DartifactIdonvif -Dversion1.0.7…

Linux基础操作三:Linux操作命令-目录文件操作

1、关机和重启 关机shutdown -h now 立刻关机shutdown -h 5 5分钟后关机poweroff 立刻关机 重启shutdown -r now 立刻重启shutdown -r 5 5分钟后重启reboot 立刻重启 2、帮助 --help命令shutdown --help&#xff1a;…

kubernetes(k8s)容器内无法连接同所绑定的Service ClusterIP问题记录

kubernetes(k8s)容器内无法连接同所绑定的Service ClusterIP问题记录 1. k8s环境 k8s使用kubernetes-server-linux-amd64_1.19.10.tar.gz 二进制bin 的方式手动部署 k8s 版本: [rootmaster ~]# kubectl version Client Version: version.Info{Major:"1", Minor:&…

掌握区块链技术将推进2024年市场发展脚步

1.高收入潜力 精通区块链的人才通常享有超过全国平均水平的薪酬&#xff0c;这也反映了对于专业技能的需求正在迅速增长。无论你选择成为这个领域哪一块业务的人员&#xff0c;掌握区块链技能均可以显著提升你的收入。 2.职业多样性 无论你目前从事什么职业&#xff0c;都可…

前端项目环境的搭建

一、下载并且安装Node&#xff08;不安装node&#xff0c;就安装nvm。nvm安装教程&#xff09;&#xff1a; 1.官网下载Node&#xff1a;https://nodejs.org/en/ 2.测试nodejs安装是否成功&#xff1a; 在windows powerShell中输入node -v 和 npm -v&#xff0c;看到版本号就…

WordPress批量上传文章和自动发布文章的方法

专业介绍&#xff1a;WordPress批量上传文章技术解析 在现代数字时代&#xff0c;内容创作是网络存在的驱动力之一。对于博客作者、新闻编辑和内容管理员而言&#xff0c;高效地批量上传文章至WordPress平台是提高工作效率的一个关键方面。WordPress作为最受欢迎的内容管理系统…

福德植保无人机:农业科技的未来已来

一、引言 随着科技的不断进步&#xff0c;无人机技术已经深入到各个领域。而在农业领域&#xff0c;福德植保无人机更是引领了科技潮流&#xff0c;为农业生产带来了革命性的改变。今天&#xff0c;让我们一起来了解福德植保无人机的魅力所在。 二、福德植保无人机的优势 高效作…

无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv7开发构建电力设备螺母缺销高分辨率图像小目标检测系统

传统作业场景下电力设备的运维和维护都是人工来完成的&#xff0c;随着现代技术科技手段的不断发展&#xff0c;基于无人机航拍飞行的自动智能化电力设备问题检测成为了一种可行的手段&#xff0c;本文的核心内容就是基于YOLOv7来开发构建电力设备螺母缺销检测识别系统&#xf…