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

news2024/9/25 15:29:46

1、什么是运算符重载?

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

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

2、什么是运算符函数?

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

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

class ClassName 
{
    ...
    public
       ReturnType 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 result
      return 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 ++ operator
    void operator ++ () 
    {
        ++count;
    }
    
    // postfix version of ++ operator
    void 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 function
    Complex 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.coloradmin.cn/o/1334659.html

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

相关文章

基于SpringBoot实现一个可扩展的事件总线

基于SpringBoot实现一个可扩展的事件总线 前言 在日常开发中&#xff0c;我们经常会用到事件总线&#xff0c;SpringBoot通过事件多播器的形式为我们提供了一个事件总线&#xff0c;但是在开发中我们经常会用到其他的实现&#xff0c;比如Guava、Disruptor的。我们将基于Spri…

迪杰斯特拉算法详解

迪杰斯特拉算法详解 首先要知道的是&#xff0c;迪杰斯特拉算法是求解单源最短路径的&#xff0c;就是在一个图中&#xff08;无向图和有向图均可&#xff09;&#xff0c;指定一个源点&#xff0c;求出来这个源点到其他各个节点的最短路径。 存图 首先&#xff0c;我需要用…

HarmonyOS应用兼容稳定性云测试

兼容性测试 兼容性测试主要验证HarmonyOS应用在华为真机设备上运行的兼容性问题&#xff0c;包括首次安装、再次安装、启动、卸载、崩溃、黑白屏、闪退、运行错误、无法回退、无响应、设计约束场景。具体兼容性测试项的详细说明请参考兼容性测试标准。 兼容性测试支持TV、智能穿…

爬虫系列----Python解析Json网页并保存到本地csv

Python解析JSON 1 知识小课堂1.1 爬虫1.2 JSON1.3 Python1.4 前言技术1.4.1 range1.4.2 random1.4.3 time.sleep1.4.4 with open() as f: 2 解析过程2.1 简介2.2 打开调试工具2.3 分析网址2.3.1 网址的规律2.3.2 网址的参数 2.4 爬取第一页内容2.5 存入字典并获取2.6 循环主体数…

DolphinScheduler 介绍及系统架构

目录 一、DolphinScheduler 介绍 1.1 关于 DolphinScheduler 1.2 特性 简单易用 丰富的使用场景 High Reliability High Scalability 1.3 名词解释 1.3.1 名词解释 1.3.2 模块介绍 二、DolphinScheduler 系统架构 2.1 系统架构图 2.2 架构说明 MasterServer 该服…

【Java核心基础】一文带你了解Java中super关键字的重要作用

“super”关键字在编程中扮演着重要角色&#xff0c;它允许我们直接访问父类中的属性、方法或构造函数&#xff0c;即使子类中存在同名元素。此外&#xff0c;“super()”在子类构造函数中调用父类初始化操作&#xff0c;确保父类属性正确初始化。有时&#xff0c;“super”还可…

Python 爬虫之下载视频(五)

爬取第三方网站视频 文章目录 爬取第三方网站视频前言一、基本情况二、基本思路三、代码编写四、注意事项&#xff08;ffmpeg&#xff09;总结 前言 国内主流的视频平台有点难。。。就暂且记录一些三方视频平台的爬取吧。比如下面这个&#xff1a; 一、基本情况 这次爬取的方…

OpenHarmony之内核层解析~

OpenHarmony简介 技术架构 OpenHarmony整体遵从分层设计&#xff0c;从下向上依次为&#xff1a;内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开&#xff0c;在多设备部署场景下&#xff0c;支持根据实际需求裁剪某些非必要的组件…

【RocketMQ】Console页面报错:rocketmq remote exception,connect to xxx failed.

现象 console报错&#xff0c;无法连接该节点&#xff0c;把该节点杀掉&#xff0c;还是继续报错&#xff0c;重启之后&#xff0c;报错的端口变成11911。 分析 正常一个broker会启动三个端口&#xff0c;不同版本的规律不太一样&#xff0c;4.X版本是&#xff1a; 配置文件…

如何使用ScrapySharp下载网页内容

C#简介 C#是一种由微软开发的通用、面向对象的编程语言。它结合了C和C的优点&#xff0c;并封装了Java的一些特性。C#被广泛评价Windows平台的软件开发&#xff0c;包括Web应用、桌面应用和游戏开发等领域。 使用场景 在网络数据挖掘和信息收集的过程中&#xff0c;我们需要…

3D模型如何制作透明玻璃材质

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 1、什么是玻璃材质 在3D建模和渲染中&#xff0c;玻璃是一种非常常见…

【期末复习】微信小程序复习大纲( 1- 5 章)

前言&#xff1a; 这周开始进入期末复习周&#xff0c;没时间看C/C、linux等知识了&#xff0c;先把期末考试必考的知识捋一遍。 目录 第一章 微信小程序入门 一、填空题 二、判断题 三、选择题 四、简答题 第二章 微信小程序页面制作 一、填空题 二、判…

【六大排序详解】中篇 :选择排序 与 堆排序

选择排序 与 堆排序 选择排序 选择排序 与 堆排序1 选择排序1.1 选择排序原理1.2 排序步骤1.3 代码实现 2 堆排序2.1 堆排序原理2.1.1 大堆与小堆2.1.2 向上调整算法2.1.3 向下调整算法 2.2 排序步骤2.3 代码实现 3 时间复杂度分析 Thanks♪(&#xff65;ω&#xff65;)&#…

智慧交通应用钡铼技术无线工业边缘路由网关R10A

智慧交通应用中&#xff0c;无线工业边缘路由网关扮演着至关重要的角色。在这方面&#xff0c;钡铼技术无线工业边缘路由网关R10A被广泛应用于交通管理系统中&#xff0c;它具备一路RS485、一路WAN、一路LAN、4G和WiFi等功能。本文将详细介绍R10A的参数以及在智慧交通领域的应用…

蓝桥题库(X图形(矩阵))

题目剖析&#xff1a; 简单来说就是找到一个由字母组成的X图形&#xff0c;且每个边上的字母都与中心点的字母相同 算法设计&#xff1a; 1.从中心点向外辐射&#xff0c;每找到一个这样的图形&#xff0c;则次数加一 2.从最外层向中心点靠拢&#xff0c;如果中间遇到不满足…

Unity Shader Early-Z技术

Unity Shader Early-Z技术 Early-Z技术Unity渲染顺序总结Alpha Test&#xff08;Discard&#xff09;在移动平台消耗较大的原因 Early-Z技术 传统的渲染管线中&#xff0c;ZTest其实是在Blending阶段&#xff0c;这时候进行深度测试&#xff0c;所有对象的像素着色器都会计算一…

外汇天眼:交易高手!是这样炼成的!

在外汇市场中&#xff0c;那些总是赚的“盆满钵满”的外汇投资高手实在是让人羡慕不已&#xff0c;他们能够准确预测市场走势&#xff0c;抓住每一个交易机会&#xff0c;实现高收益&#xff0c;很多投资新手因此也想入市&#xff0c;但即使是这样&#xff0c;还是有很多新手对…

关于标准那些事——第五篇 两仪

国家标准的编写&#xff0c;对于标准的名称和结构&#xff0c;很多人往往是不那么在意的&#xff0c;但这恰恰也是非常重要的点&#xff0c;今天就给大家分享一下这太极所生的“两仪”。我会用最精简的文字概括出核心内容&#xff0c;让大家有一个初步且完整的概念&#xff0c;…

规律生活指南:数据可视化助你游刃有余

随着信息时代的到来&#xff0c;我们生活在一个数据海洋中&#xff0c;每天都会面对大量的信息和数字。在这个信息过载的时代&#xff0c;如何从杂乱的数据中找到规律&#xff0c;让生活更加有序成为了一项挑战。而数据可视化作为一种强大的工具&#xff0c;不仅能够帮助我们理…

算法基础之数字三角形

数字三角形 核心思想&#xff1a;线性dp 集合的定义为 f[i][j] –> 到i j点的最大距离 从下往上传值 父节点f[i][j] max(f[i1][j] , f[i1][j1]) w[i][j] 初始化最后一层 f w #include <bits/stdc.h>using namespace std;const int N 510;int w[N][N],f[N][…