C/C++学习笔记十三 C++中的重载运算符

1、什么是运算符重载?

        运算符重载是 C++ 中的一项功能,使运算符(例如 +、- 等)能够处理用户定义的数据类型。这种机制称为编译时多态性,并提供了为不同数据类型定制运算符行为的优点。

        例如,我们可以重载“+”运算符来执行整数加法、字符串串联以及复数加法。这增强了运算符的多功能性,使他们能够对更广泛的数据类型进行操作。

2、什么是运算符函数?

        运算符函数是一种专门类型的函数,它为特定运算符提供替代实现。它的语法与常规函数类似,但其名称以“operator”关键字开头,后跟运算符符号。

        我们可以为同一个运算符定义多个运算符函数,这些函数可以根据它们所使用的操作数的数量和类型来区分。例如,“+”运算符可以针对整数、字符串和复数具有不同的运算符函数实现。这允许对操作员进行定制以满足特定要求。

class ClassName 
{...publicReturnType operator OperatorSymbool(argument list) {// Implementation logic} ...
};

        ReturnType: 运算符函数返回值的类型。

        运算符:编程语言中用于执行特定操作的关键字。

        OperatorSymbol:程序中重载的运算符的符号。

        参数列表:调用函数时传递给函数的参数列表。

3、使用运算符重载将两个复数相加

        假设我们不使用运算符重载并且想要将两个复数相加。我们可以通过创建一个名为“Complex”的复数类来实现这一点。在类内部,我们定义了一个名为“add”的公共方法,它执行两个复数的加法。此方法将接受两个复数作为参数,并将它们相加的结果作为新的复数返回。

class Complex {public:Complex add(Complex c1, Complex c2) {// Perform addition of c1 and c2 and return the resultreturn result;}
};//This approach works.
//But it requires us to call add method
Complex c1, c2, res;
res = c1.add(c1, c2);

        众所周知,运算符重载允许我们更改运算符的行为以处理用户定义的数据类型。因此,对于复数重载“+”运算符,我们可以在“Complex”类中定义一个运算符重载函数。

        此函数将指定“+”运算符与复数一起使用时的新行为。该函数可以定义为类的成员函数或友元函数,具体取决于运算符及其所操作的操作数的具体要求。

        定义完运算符函数后,我们现在可以使用简单的语句将两个复数 c1 和 c2 相加:res = c1 + c2,这相当于 res = c1.operator+ (c2)。这使得代码更直观、更容易理解。

#include <iostream>
using namespace std;class Complex {private:int real, imag;public:Complex(int r = 0, int i = 0) {real = r;imag = i;}Complex operator + (Complex c) {Complex temp;temp.real = real + c.real;temp.imag = imag + c.imag;return temp;}int getReal(){return real;}int getImag(){return imag;}
};int main() {Complex c1(4, 7);Complex c2(3, 5);Complex res;res = c1 + c2;cout << "Result: " << res.getReal() << " + " << res.getImag() << "i" << endl;return 0;
}//output Result: 7 + 12i

        我们还可以将函数签名写成如下:

Complex operator + (const Complex& c)

        这个版本与之前的版本有几个显着的区别:

  • 参数“c”使用“&”运算符通过引用传递,这意味着该函数将接收到原始对象的直接链接而不是副本。
  • 参数“c”也被指定为“const”,表示该函数不能更改它所传递的对象。

        这些修改被认为是最佳实践,原因如下:

  • 通过引用传递对象,函数可以访问原始对象而无需创建重复对象,从而提高效率并避免创建新对象的不必要的开销。
  • 将对象指定为“const”有助于防止对该对象进行意外修改,从而降低代码中出现错误和意外行为的风险。

4、重载加法运算符的另一个例子

class opr 
{private:int a;float b;public:opr(int a, float b) {this->a = a;this->b = b;}opr operator + (opr test) {opr tmp(0, 0.0);tmp.a = a + test.a;tmp.b = b + test.b;return tmp;}void show() {cout << a << " " << b << '\n';}
};int main() 
{opr obj1(1, 3.3);opr obj2(2, 1.5);opr obj3;obj3 = obj1 + obj2;obj3.show();return 0;
}

5、运算符重载的一些规则

        在 C++ 中重载运算符时,需要记住几个重要规则:

        1、至少其中一个操作数必须是用户定义的数据类型。

        2、只有内置运算符才能重载。这意味着我们无法创建新的运算符,只能更改现有的运算符以使其工作方式不同。

        3、重载运算符不能有默认参数,空参数列表“()”除外。

        4、重载运算符不会影响其优先级或结合性。

        5、操作数的数量无法更改。例如,一元运算符保持一元,二元运算符保持二元。

        6、编译器会自动为每个类重载赋值运算符“=”。换句话说,不需要为赋值运算符创建单独的运算符函数。我们可以使用它来复制同一类的对象,类似于使用复制构造函数。

        7、重载运算符时,正确且一致地使用它们以使代码更具可读性和易于理解性至关重要。

6、一元运算符的运算符重载

        一元运算符是对单个操作数进行操作的运算符。自增运算符“++”和自减运算符“--”是一元运算符的示例。例如,增量运算符“++”将其操作数的值增加1。它可以用作前缀运算符(放置在操作数之前)或后缀运算符(放置在操作数之后)。

        例如:

int x = 5;
// x is incremented to 6, and y is set to 6
int y = ++x;
// x is incremented to 7, but z is set to the original value of x (6)
int z = x++;

        类似地,减运算符“--”将其操作数的值减1。它也可以用作前缀或后缀运算符。例如:

int x = 5;
// x is decremented to 4, and y is set to 4
int y = --x;
// x is decremented to 3, but z is set to the original value of x (4)
int z = x--;

7、重载自增运算符(++)的实现代码

        在下面的代码中,我们定义了一个名为“Value”的类,其中包含一个私有成员变量“count”。我们还定义了一个构造函数,将该成员变量初始化为值 2。在类内部,我们将“operator++”函数定义为成员函数,该函数被重载两次(带和不带 int 参数)。这些函数将“count”成员变量的值加 1。

        在 main 函数中,我们创建一个“Value”对象 (v) 并对其多次使用“++”运算符。然后,我们使用“getCount”方法来检索“count”成员变量的值。

class Value 
{private:int count;public:Value() : count(2) {}// prefix version of ++ operatorvoid operator ++ () {++count;}// postfix version of ++ operatorvoid operator ++ (int) {++count;}int getCount() {return count;}
};int main() 
{Value v;v++;cout << v.getCount() << "\n";++v;++v;cout << v.getCount() << "\n";return 0;
}//output 
//3
//5

        一元运算符函数的前缀和后缀版本之间的唯一区别是参数列表。前缀版本不带参数,而后缀版本带一个“int”类型的参数。该参数实际上并不用于传递整数值,而是向编译器发出信号,指示该函数应用于重载运算符的后缀形式。

8、C++中实现运算符重载的三种方法

        (1)、通过成员函数重载运算符

        成员函数是在类内部定义并作用于该类的对象的函数。关于运算符重载,一元运算符(对单个参数进行操作的运算符)在其列表中没有参数,而二元运算符(对两个参数进行操作的运算符)只有一个参数。

class Complex 
{private:double real;double imag;public:Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}// overload the + operator as a member functionComplex operator + (const Complex& other) const {return Complex(real + other.real, imag + other.imag);}void print() const {cout << real << " + " << imag << "i" << endl;}
};int main() 
{Complex c1(1, 2);Complex c2(3, 4);Complex c3 = c1 + c2;c3.print();return 0;
}
        (2)、通过友元函数重载运算符

        友元函数不是类的成员,但可以直接访问私有和受保护成员,并且可以在类的私有或公共部分中声明。与成员函数相比,它提供了更大的灵活性。

        换句话说,如果运算符函数需要访问类的私有和受保护成员,则可以将其定义为友元函数。在这种情况下,一元运算符有一个参数,而二元运算符有两个参数。

class Complex 
{private:double real;double imag;public:Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}friend Complex operator + (const Complex& c1, const Complex& c2);void print(){cout << real << " + " << imag << "i" << endl;}
};// overload the + operator as a friend function
Complex operator + (const Complex& c1, const Complex& c2) 
{return Complex(c1.real + c2.real, c1.imag + c2.imag);
}int main() 
{Complex c1(1, 2);Complex c2(3, 4);Complex c3 = c1 + c2;c3.print();return 0;
}
        (3)、通过非成员函数重载运算符

        非成员函数不是类的成员,无权访问私有成员和受保护成员。

class Complex 
{public:double real;double imag;Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}void print() const {cout << real << " + " << imag << "i" << endl;}
};// overload the + operator as a non-member function
Complex operator + (const Complex& c1, const Complex& c2) 
{return Complex(c1.real + c2.real, c1.imag + c2.imag);
}int main() 
{Complex c1(1, 2);Complex c2(3, 4);Complex c3 = c1 + c2;c3.print();return 0;
}

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

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

相关文章

【算法题】20. 有效的括号

题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类…

VueRouter的路由模式有哪几种

VueRouter的路由模式有三种&#xff1a;hash模式、history模式和abstract模式。 hash模式&#xff1a;在URL中的路径部分以 # 符号开头。比如&#xff1a;http://www.example.com/#/home。在hash模式下&#xff0c;URL的hash部分的改变不会导致浏览器向服务器发送请求&#xff…

cpp初始化一个结构体

一开始我是直接定义一个结构体指针&#xff0c;给其进行初始化&#xff0c;但是一直报错&#xff0c;最后改为结构体后就好了 结构体定义&#xff1a; struct graph {// Number of edges in the graphint num_edges;// Number of vertices in the graphint num_nodes;// The n…

Maven - expected START_TAG or END_TAG not TEXT (position: TEXT seen …

问题描述 expected START_TAG or END_TAG not TEXT (position: TEXT seen … 原因分析 由于我们复制 pom.xml 过程中&#xff0c;空格的格式不规范&#xff0c;或者格式有问题&#xff0c;maven 会出现加载错误&#xff0c;导致我们的 jar 包也不能正确导入而报红 解决方案 只…

使用Vue3开发学生管理系统模板2 新增学生信息

实现新增学生的功能 第一步&#xff1a;点击新增按钮&#xff0c;弹窗新增学生的页面 function openNew() {student.value {id: "1",student_id: "1",chinese_id: "5222xxx",name: "张三",age: 13,gender: "男",height: …

Flink1.17实战教程(第二篇:DataStream API)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…

双向循环链表实现C语言关键字中英翻译机 ฅ( ̳• · • ̳ฅ)

目录 1.双向循环链表的声明与定义&#xff1a; 2. 创建链表并对节点中的数据赋初值 3. 插入节点并链接 4.中英翻译 5. 小游戏的实现 6.菜单的实现 7. 释放内存 8.在主函数中用刚才定义的函数实现各种代码 输入样例&#xff1a; 实现方法&#xff1a;双向循环链表来实…

对话面试官----jvm模型

JVM&#xff08;Java Virtual Machine&#xff09;是 Java 虚拟机的缩写&#xff0c;它是一个运行 Java 字节码的虚拟计算机。JVM 提供了一个平台独立的执行环境&#xff0c;能够在不同的操作系统上运行 Java 程序。JVM 模型由类加载器、运行时数据区域、执行引擎等组成&#x…

CentOS上安装MySQL 8.0的详细教程

CentOS上安装MySQL 8.0的详细教程 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我将为大家分享一篇关于在CentOS上安装MySQL 8.0的详细教程。MySQL是一个强大…

UDP协议工作原理及实战(二)UDP客户端代码实现

这个是一个测试我们写的函数是否正确。 启动服务&#xff1a;这里边的udpsocket->bind(port)就是对端口号进行连接。

开发知识点-Weblogic

Weblogic 介绍CVE_2018_2628poc-yaml-weblogic-ssrfpoc-yaml-weblogic-cve-2017-10271poc-yaml-weblogic-cve-2019-2725poc-yaml-weblogic-cve-2019-2729-1poc-yaml-weblogic-cve-2019-2729-2poc-yaml-weblogic-cve-2020-14750poc-yaml-weblogic-local-cve-2022-21371-file-inc…

链路层、网络层、传输层、应用层长度

参考&#xff1a;链路层、网络层、传输层、应用层长度 链接&#xff1a;https://blog.csdn.net/qq_41658597/article/details/120683870 目录 1、概述2、TCP、UDP数据包最大值的确定3、TCP、UDP数据包最小值的确定4、实际应用IP层 1、概述 首先要看TCP/IP协议&#xff0c;涉及到…

2024 年软件工程将如何发展

软件开发目前正在经历一场深刻的变革&#xff0c;其特点是先进自动化的悄然但显着的激增。这一即将发生的转变有望以前所未有的规模简化高质量应用程序的创建和部署。 它不是单一技术引领这一演变&#xff0c;而是创新的融合。从人工智能(AI) 和数字孪生技术&#xff0c;到植根…

Feature Prediction Diffusion Model for Video Anomaly Detection 论文阅读

Feature Prediction Diffusion Model for Video Anomaly Detection论文阅读 Abstract1. Introduction2. Related work3. Method3.1. Problem Formulation3.2. Feature prediction diffusion module 3.3. Feature refinement diffusion module4. Experiments and discussions4.1…

数据探查系列:如何进行有意义的探索性数据分析(EDA)

如何进行有意义的探索性数据分析&#xff08;EDA&#xff09; 目录 1. 设置 1.1 导入库1.2 导入数据1.3 数据集特征1.4 数据集属性 2. 探索训练集和测试集 2.1 训练集 - 快速概览2.2 训练集 - 基本统计2.3 测试集 - 快速概览2.4 测试集 - 基本统计 3. 特征分布4. 数据不平衡检查…

什么是迁移学习(Transfer Learning)?定义,优势,方法

迄今为止&#xff0c;大多数人工智能&#xff08;AI&#xff09;项目都是通过监督学习技术构建的。监督学习是一种从无到有构建机器学习&#xff08;ML&#xff09;模型的方法&#xff0c;它对推动AI发展起到了关键作用。然而&#xff0c;由于需要大量的数据集和强大的计算能力…

openmediavault(OMV) (19)云相册(3)mt-photos

简介 MT Photos是一款为Nas用户量身打造的照片管理系统。通过AI技术,自动将您的照片整理、分类,包括但不限于时间、地点、人物、照片类型。可以在任何支持Docker的系统中运行它。详情可查看mtmt.tech官网,mt-photos是付费订阅使用的,也可以一次性付费永久使用,具体使用mt…

机器学习系列--R语言随机森林进行生存分析(1)

随机森林&#xff08;Breiman 2001a&#xff09;&#xff08;RF&#xff09;是一种非参数统计方法&#xff0c;需要没有关于响应的协变关系的分布假设。RF是一种强大的、非线性的技术&#xff0c;通过拟合一组树来稳定预测精度模型估计。随机生存森林&#xff08;RSF&#xff0…

观察者模式概述

观察者模式,它用于建立一种对象与对象之间的依赖关系&#xff0c; 一个对象发生改变将自动通知其他对象&#xff0c; 其他对象将相应做出反应。在观察者模式种&#xff0c;发生改变的对象称为观察目标&#xff0c; 而被通知的对象称为观察者&#xff0c;一个观察目标可以对应多…

docker学习(二十、network使用示例host、none)

文章目录 一、host应用示例总结 二、none应用示例总结 network相关内容&#xff1a; docker学习&#xff08;十八、network介绍&#xff09; docker学习&#xff08;十九、network使用示例bridge&#xff09; docker学习&#xff08;二十、network使用示例host、none&#xff0…