c++:类和对象(5),运算符重载

news2024/11/16 5:44:21

目录

运算符重载概念:

+运算符重载

    1.成员函数重载+号 

2.全局函数重载+号

打印结果:

<<运算符重载

 递增运算符重载

简单例子

输出结果为:

 赋值运算符重载

如何重载

输出结果为:

什么时候重载 

 关系运算符重载

简单例子:

输出结果如下:

函数调用运算符重载 

简单例子

输出结果为:


运算符重载概念:

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

+运算符重载

    1.成员函数重载+号 

#include<iostream>
using namespace std;

class person 
{
public:

	// 1. 成员函数重载加号运算符
    // 这里重载了加号运算符,使得两个person对象相加时,可直接通过加号进行操作
	person operator+(person& p)
	{
		person temp;
		temp.m_a = this->m_a + p.m_a; // 对m_a进行相加操作
		temp.m_b = this->m_b + p.m_b; // 对m_b进行相加操作
		return temp; // 返回相加后的结果
	}
	
	int m_a;
	int m_b;

};

void test01()
{
	person p1;
	p1.m_a = 10;
	p1.m_b = 20;
	person p2;
	p2.m_a = 10;
	p2.m_b = 20;

	person p3 = p1 + p2;  // 将p1和p2相加的结果赋值给p3

	cout << p3.m_a << endl; // 输出p3的m_a值
	cout << p3.m_b << endl; // 输出p3的m_b值
}

int main()
{
    test01(); // 调用test01函数进行测试
    system("pause"); // 暂停系统, Windows下使用

    return 0;
}

以上代码定义了一个person类,并重载了+运算符,使得两个person对象可以通过+进行相加操作。测试时创建了两个person对象p1p2,将它们相加的结果赋值给p3,然后输出p3的成员变量m_am_b的值。

2.全局函数重载+号

#include <iostream>
using namespace std;

class MyNumber 
{
private:
    int value;

public:
    MyNumber(int val) : value(val) {}

    int getValue() const { return value; }

    // 友元函数,全局函数重载加号运算符
    friend MyNumber operator+(const MyNumber& num1, const MyNumber& num2);
};

// 全局函数重载加号运算符
MyNumber operator+(const MyNumber& num1, const MyNumber& num2) 
{
    int sum = num1.value + num2.value;
    return MyNumber(sum);
}

int main() 
{
    MyNumber num1(5);
    MyNumber num2(7);

    MyNumber sum = num1 + num2; // 使用重载的加号运算符进行相加操作

    cout << "num1 = " << num1.getValue() << endl;
    cout << "num2 = " << num2.getValue() << endl;
    cout << "sum = " << sum.getValue() << endl;

    return 0;
}

打印结果:

在上述示例代码中,定义了一个名为MyNumber的类,其中包含一个私有成员变量value和构造函数。

为了使全局函数能够访问MyNumber类的私有成员,我们将该全局函数声明为MyNumber类的友元函数。在这个友元函数operator+中,我们重载了加号运算符,实现了两个MyNumber对象相加操作,并返回一个新的MyNumber对象作为结果。

main函数中,我们创建了两个MyNumber对象num1num2,然后使用重载的加号运算符将它们相加,将结果赋值给sum。最后,通过getValue成员函数分别输出num1num2sum的值。

总结:对于内置的数据类型的表达式的运算符是不可能改变的


<<运算符重载

#include <iostream>
using namespace std;

class Point 
{
private:
    int x, y;

public:
    Point(int a = 0, int b = 0) : x(a), y(b) {}

    int getX() const { return x; }
    int getY() const { return y; }

    // 友元函数,全局函数重载输出运算符
    friend ostream& operator<<(ostream& os, const Point& p);
};

// 全局函数重载输出运算符
ostream& operator<<(ostream& os, const Point& p) 
{
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

int main() 
{
    Point p(3, 5);

    cout << "The coordinates of p: " << p << endl;

    return 0;
}

输出结果为:

The coordinates of p: (3, 5)

在上述示例代码中,定义了一个名为Point的类,其中包含了两个私有成员变量xy,以及构造函数和获取成员变量的成员函数。

为了实现以自定义的方式输出Point类对象,我们重载了输出运算符<<。全局函数operator<<接受一个ostream对象os和一个Point对象p作为参数。在函数体中,我们使用os对象来输出p的坐标信息。

main函数中,我们创建了一个Point对象p,然后使用重载的输出运算符将p输出到标准输出流中。输出的结果将会是形如(3, 5)的坐标信息。


 递增运算符重载

简单例子

#include <iostream>
using namespace std;

class MyNumber 
{
private:
    int value;

public:
    MyNumber(int val) : value(val) {}

    int getValue() const 
    {
        return value;
    }

    // 重载前置递增运算符
    MyNumber& operator++() 
    {
        value++;
        return *this;
    }

    // 重载后置递增运算符
    MyNumber operator++(int) 
    {
        MyNumber temp(value);
        value++;
        return temp;
    }
};

int main() 
{
    MyNumber num(5);

    cout << "原始值:" << num.getValue() << endl;

    MyNumber preIncrement = ++num; // 前置递增运算符
    cout << "前置递增后的值:" << num.getValue() << endl;
    cout << "前置递增值:" << preIncrement.getValue() << endl;

    MyNumber postIncrement = num++; // 后置递增运算符
    cout << "后置递增后的值:" << num.getValue() << endl;
    cout << "后置递增值:" << postIncrement.getValue() << endl;

    return 0;
}

在上述示例代码中,定义了一个名为MyNumber的类,其中包含一个私有成员变量value和构造函数。

MyNumber类中,我们重载了前置递增运算符(++num)和后置递增运算符(num++)。前置递增运算符函数返回一个引用,先将value成员变量加1,然后返回递增后的对象。后置递增运算符函数接受一个额外的整型参数(通常为0),用于区分前置和后置递增运算符,创建一个临时对象保存递增前的值,然后将value成员变量加1,并返回临时对象。

注意:区别前置加加和后置加加的返回类型,看是否错误的进行了重载函数。

main函数中,我们创建了一个MyNumber对象num,然后进行前置递增运算和后置递增运算。我们将递增后的num对象的值以及返回的递增前的对象的值进行输出。

输出结果为:

原始值:5
前置递增后的值:6
前置递增值:6
后置递增后的值:7
后置递增值:6

总结:前置++返回引用,后置++返回值, 还要加参数,区别重置函数。


 赋值运算符重载

如何重载

#include <iostream>
using namespace std;

class MyClass 
{
private:
    int value;
public:
    MyClass(int val) : value(val) {}

    int getValue() const 
    {
        return value;
    }

    // 赋值运算符重载
    MyClass& operator=(const MyClass& other) 
        {
        if (this != &other) { // 检查自我赋值
            value = other.value;
        }
        return *this;
    }
};

int main() 
{
    MyClass obj1(5);
    MyClass obj2(10);

    cout << "obj1的初始值: " << obj1.getValue() << endl;
    cout << "obj2的初始值: " << obj2.getValue() << endl;

    obj1 = obj2; // 使用赋值运算符将obj2的值赋给obj1

    cout << "赋值后,obj1的值: " << obj1.getValue() << endl;

    return 0;
}

在上述示例代码中,我们在MyClass类中重载了赋值运算符(operator=)。该函数接收一个常量引用参数 other,表示赋值运算符右侧的对象。

在重载函数中,我们首先进行自我赋值检查,以避免在赋值时发生错误。然后,将other对象的值赋给this指针所指向的对象的value成员变量。

main函数中,我们创建了两个MyClass对象 obj1 和 obj2。然后使用赋值运算符将 obj2 的值赋给了 obj1。最后输出 obj1 的值进行验证。

输出结果为:

obj1的初始值: 5
obj2的初始值: 10
赋值后,obj1的值: 10

什么时候重载 

  • 当类中含有指针成员变量时,需要深拷贝对象的内容而不只是复制指针的地址。通过重载赋值运算符,可以在对象赋值时自定义深拷贝的行为,确保指针所指的资源得到正确的复制和释放。

  • 当类中存在动态分配的资源,如文件句柄、网络连接等,需要在对象赋值时确保资源的正确释放和转移。

  • 当类中含有其他类对象作为成员变量时,通过重载赋值运算符,可以实现对成员对象的赋值操作。

  • 当使用类的对象进行赋值操作时,希望自定义赋值的行为,例如执行额外的检查、记录操作日志等。


 关系运算符重载

简单例子:

#include <iostream>
using namespace std;

class Student 
{
private:
    int age;

public:
    Student(int studentAge) : age(studentAge) {}

    // 重载等于运算符
    bool operator==(const Student& other) const 
    {
        return (age == other.age);
    }

    // 重载小于运算符
    bool operator<(const Student& other) const 
    {
        return (age < other.age);
    }

    int getAge() const 
    {
        return age;
    }
};

int main() 
{
    Student s1(20);
    Student s2(18);
    Student s3(20);

    cout << "s1的年龄: " << s1.getAge() << endl;
    cout << "s2的年龄: " << s2.getAge() << endl;
    cout << "s3的年龄: " << s3.getAge() << endl;

    // 使用重载的等于运算符
    if (s1 == s2) 
    {
        cout << "s1 等于 s2" << endl;
    } 
    else 
    {
        cout << "s1 不等于 s2" << endl;
    }

    if (s1 == s3)  
    {
        cout << "s1 等于 s3" << endl;
    } 
    else 
    {
        cout << "s1 不等于 s3" << endl;
    }

    // 使用重载的小于运算符
    if (s1 < s2) 
    {
        cout << "s1 小于 s2" << endl;
    } 
    else 
    {
        cout << "s1 不小于 s2" << endl;
    }

    if (s2 < s3) 
    {
        cout << "s2 小于 s3" << endl;
    } 
    else 
    {
        cout << "s2 不小于 s3" << endl;
    }

    return 0;
}

在上述代码中,我们定义了一个 Student 类,其中包含一个私有的 age 成员变量和对应的访问器函数 getAge()

我们重载了等于运算符(==)和小于运算符(<)。在重载函数中,我们比较了两个 Student 对象之间的年龄。

在 main 函数中,我们创建了三个 Student 对象 s1s2 和 s3,并输出他们的年龄。

接下来,我们使用重载的等于运算符来比较 s1 和 s2,以及 s1 和 s3 的年龄是否相等,并输出结果。

然后,我们使用重载的小于运算符来比较 s1 和 s2,以及 s2 和 s3 的年龄大小,并输出结果。

输出结果如下:

s1的年龄: 20
s2的年龄: 18
s3的年龄: 20
s1 不等于 s2
s1 等于 s3
s1 不小于 s2
s2 小于 s3

函数调用运算符重载 

 由于重载后的使用的方式非常像函数的调用,因此称为仿函数。

简单例子

#include <iostream>
using namespace std;

class MyFunction 
{
public:
    int operator()(int a, int b) 
    {
        return a + b;
    }
};

int main() 
{
    MyFunction myFunc;

    int result = myFunc(2, 3); // 调用重载的函数调用运算符
    cout << "调用结果: " << result << endl;

    return 0;
}

在上述代码中,我们定义了一个名为 MyFunction 的类,并重载了函数调用运算符 operator()。重载后的函数调用运算符将两个参数相加,并返回结果。

在 main 函数中,我们创建了 MyFunction 类的对象 myFunc。然后,我们将对象 myFunc 当作函数一样进行调用,传递两个参数,并将结果存储在 result 变量中。

输出结果为:

调用结果: 5

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

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

相关文章

【并发编程】同步模式之保护性暂停

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳中求进&#xff0c;晒太阳 同步模式之保护性暂停 这个模式用到的基础就是wait-notify 详情可以看这篇文章》:【并发编程】wait/notify 即Guarded Suspension,用在一个线…

鸿蒙开发 状态管理

最近学习鸿蒙开发。 状态管理&#xff1a; State -> Prop 单向传递&#xff1b; stateprop: State -> Prop 单向传递 State -> Link 双向传递&#xff1b;

Windows脚本:监控并自动重启某个进程

Windows脚本&#xff1a;监控自动并重启某个进程 一、简介二 .bat脚本方式2.1 编制脚本2.2 创建并运行脚本2.3 设置关闭cmd窗口 三、使用VBScript脚本方式3.1 编制脚本3.2 运行脚本 四、设置脚本开机自启动五、某些软件加入启动项后&#xff0c;开机不会自动启动的解决方法 在实…

代码随想录算法训练营第十四天|二叉树基础-二叉树迭代-二叉树

文章目录 二叉树基础二叉树种类满二叉树完全二叉树二叉搜索树平衡二叉搜索树 二叉树的存储方式链式存储顺序存储 二叉树的遍历方式二叉树的定义 二叉树的递归遍历144.二叉树的前序遍历代码&#xff1a; 145.二叉树的后序遍历代码&#xff1a; 94. 二叉树的中序遍历代码 二叉树的…

Linux中并发程序设计

进程的创建和回收 进程概念 概念 程序 存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09; 静态的 进程 执行一个程序所分配的资源的总称 动态的进程和程序比较 注&#xff1a;进程是存在RAM中&#xff0c;程序是存放在ROM(flash)中的进程内容 BSS段&#xff…

Unity通用渲染管线升级URP、HDRP

Unity通用渲染管线升级URP、HDRP 一、Build-in Pipline升级到 URP 一、Build-in Pipline升级到 URP 安装URP包 升级所有材质&#xff08;升级完成后材质会变成紫红色&#xff0c;Shader丢失&#xff0c;此为正常现象&#xff09; 创建 UniversalRenderPipelineAsset 配置文…

Origin:调整颜色刻度线间距和小数点

如何设置或修改Color Scale 的间距和小数位&#xff1f; 答&#xff1a;&#xff08;1&#xff09;更改间距&#xff1a;左键双击刻度标线——级别——“显示主刻度在”下选择自定义级别——在“值”输入自定义间距增量。 &#xff08;2&#xff09;更改小数点个数&#xff1a…

嵌入式-stm32-江科大-OLED调试工具

文章目录 一&#xff1a;OLED调试工具1.1 OLED显示屏介绍1.2 实验&#xff1a;在OLED显示屏的使用1.3 自己新增功能测试道友&#xff1a;今天没有开始的事&#xff0c;明天绝不会完成。 一&#xff1a;OLED调试工具 1.1 OLED显示屏介绍 学习任何一门语言就需要进行调试&#…

民用激光雷达行业简析

01. 激光雷达是“机器之眼” • 激光雷达是一个通过发射激光并接受发射激光同时对其进行信号处理&#xff0c;从而获得周边物体距离等信息的主动测量装置。 • 激光雷达主要由光发射、光扫描、光接收三大模块组成。光发射模块集成了驱动、开关和光源等芯片。光接收模块集成了…

浏览器安装证书,使用burp抓取任意https协议的流量

抓包显示都是http的。 接受风险后&#xff1a; 给burp加证书&#xff1a; 点击后会让你下载&#xff0c;证书已下载 证书长这个样子~~~ 浏览器设置中直接搜索证书&#xff1a; 勾选信任&#xff1a; 会到之前加载不出的页面刷新就可以看到加载出来图片等&#xff1a; 此时看到…

【大数据】Flink 系统架构

Flink 系统架构 1.Flink 组件1.1 JobManager1.2 ResourceManager1.3 TaskManager1.4 Dispatcher 2.应用部署2.1 框架模式2.2 库模式 3.任务执行4.高可用设置4.1 TaskManager 故障4.2 JobManager 故障 Flink 是一个用于状态化并行流处理的分布式系统。它的搭建涉及多个进程&…

服务器的组成

服务器的重要结构组成 家用电脑组成&#xff1a; CPU、主板、内存条、显卡、硬盘、电源、风扇、网卡、显示器、机箱、键盘鼠标等等。 CPU CPU是电脑的大脑&#xff0c; CPU发展史&#xff1a; 32 位CPU&#xff1a;最大的内存寻址地址2^32&#xff0c;大约4G的大小。 CP…

【基础算法练习】二分模板

文章目录 二分模板题二分的思想C 版本的二分整数二分模板 Golang 版本的二分整数二分模板 例题&#xff1a;在排序数组中查找元素的第一个和最后一个位置题目描述C 版本代码Golang 版本代码 二分模板题 704. 二分查找&#xff0c;这道题目是最经典的二分查找&#xff0c;使用于…

Git操作指南

Git操作指南 Git是一款非常强大的版本控制工具&#xff0c;可以帮助开发者管理代码的版本、协同开发以及进行代码的发布。以下是一些常见的Git操作指南。 基本操作 初始化一个Git仓库 git init添加文件到暂存区 git add 文件名提交更改到本地仓库 git commit -m "提…

Simulink|光伏并网逆变器低电压穿越仿真模型

目录 主要内容 模型研究 1.模型总览 2.boost模块 3.Inverter模块 4.控制模块 5.信号模块 结果一览 下载链接 主要内容 该模型为光伏逆变器低电压穿越仿真模型&#xff0c;采用boost加NPC拓扑结构&#xff0c;基于MATLAB/Simulink建模仿真。模型具备中点平衡…

CentOS安装Redis教程-shell脚本一键安装配置

文章目录 前言一、Redis单机版安装教程1. 复制脚本2. 增加执行权限3. 执行脚本 二、Redis扩展集群版安装教程1. 安装Redis单机版2. 复制脚本3. 增加执行权限4. 执行脚本5. 测试6. redis_cluster.sh 命令6.1 启动Redis扩展集群6.2 停止Redis扩展集群6.3 查看Redis扩展集群节点信…

在虚拟时空对话邓中亮院士,元宇宙访谈节目强势出圈

​​2023年12月&#xff0c;由米果集团、浙江省元宇宙产业基地联合出品的《科技领军人物的思维模式解析》访谈节目上线。在节目制作过程中&#xff0c;主持人对话“国际欧亚科学院院士、北京邮电大学邓中亮教授”&#xff0c;全程使用蓝海创意云的“vLive虚拟直播”系统进行节目…

Dubbo 3.x源码(16)—Dubbo服务发布导出源码(5)

基于Dubbo 3.1&#xff0c;详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了Dubbo 3.x源码(15)—Dubbo服务发布导出源码(4)&#xff0c;也就是Dubbo远程服务导出export方法的上半部分&#xff0c;也就是doLocalExport源码&#xff0c;将会得到一个Exporter。 现在我们…

LLM之RAG理论(七)| 高提升RAG检索的四种方法

​ RAG两大核心组件&#xff1a;检索和生成。本文将总结四种提高RAG系统检索质量的技术&#xff1a;1&#xff09;子问题查询引擎&#xff08;来自LlamaIndex&#xff09;&#xff0c;2&#xff09;RAG-Fusion、3&#xff09;RAG-end2end和4&#xff09;LoRA微调。 一、L…

司铭宇老师:门店经理培训:如何成为一位卓越的门店经理

门店经理培训&#xff1a;如何成为一位卓越的门店经理 在激烈的市场竞争中&#xff0c;门店经理作为门店的灵魂人物&#xff0c;肩负着提升门店业绩、维护品牌形象、带领团队成长等重要职责。本文将为您解析如何成为一位卓越的门店经理&#xff0c;助力您的职业生涯迈向新高峰…