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

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

八皇后问题(C语言)

了解题意 在一个8x8的棋盘上放置8个皇后&#xff0c;使得任何两个皇后都不能处于同一行、同一列或同一斜线上。问有多少种方法可以放置这8个皇后&#xff1f; 解决这个问题的目标是找到所有符合要求的皇后摆放方式&#xff0c;通常使用回溯算法来求解。回溯算法会尝试所有可能…

网格布局(大练习)

最近对网格布局研究了一下&#xff0c;写了一个简单的demo。可以参考参考~ 网格基础布局&#xff1a;github地址 挤占网格布局&#xff1a;github地址 基础网站格局&#xff1a;github地址 复杂网站格局&#xff08;方式一&#xff09;&#xff1a;github地址 复杂网站格局&am…

1.Linux快速入门

Linux快速入门 Linux操作系统简介Linux操作系统优点Linux操作系统发行版1. Red Hat Linux2. CentOS3. Ubuntu4. SUSE Linux5. Fedora Linux 32位与64位操作系统的区别Linux内核命名规则 Linux操作系统简介 Linux操作系统是基于UNIX以网络为核心的设计思想&#xff0c;是一个性…

X210 Linux开发板挂载NFS文件系统

网络搭建 采用“路由器”“有线网”来将Linux开发板和Ubuntu虚拟机连接在同一个局域网中。具体接线如下&#xff1a; Linux开发板通过网线直接连接到“路由器”的LAN接口上&#xff0c;然后笔记本电脑通过Wifi与路由器连接。 VirtualBox虚拟机网络设置 在”网线“设置界面中…

1.S32K3电源和复位

一、电源 S32K3系列芯片的电源各不相同。以S32K34x&#xff0c;S32K32x及S32K314为例。 并且该芯片支持以下特性&#xff1a; • Combination of internal and external voltage regulator options, offering RUN and Standby modes • FPM , which is used on chip-level in…

Flood Fill算法总结

算法思想 从一个起点开始&#xff0c;每一次随机选择一个新加进来的格子&#xff0c;看一下它周围能否扩展新的格子。如果能扩展&#xff0c;那么就扩展进来&#xff0c;直到不能扩展新的格子为止。当然需要判重&#xff0c;同样一个格子只能覆盖一次&#xff0c;这样能够保证时…

JVM工作原理与实战(二):字节码编辑器jclasslib

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、字节码编辑器jclasslib介绍和安装 1.介绍 2.安装 3.IntelliJ IDEA 插件安装 二、字节码编辑器jclasslib的使用 1.使用jclasslib bytecode viewer打开字节码文件 2.使用Intell…

gitLab页面打tag操作步骤

作者&#xff1a;moical 链接&#xff1a;gitLab页面打tag简单使用 - 掘金 (juejin.cn) 来源&#xff1a;稀土掘金 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 ---------------------------------------------------------------------…

对I2C总线上挂接多个AT24C02的读写操作

#include <reg51.h> // 包含51单片机寄存器定义的头文件 #include <intrins.h> //包含_nop_()函数定义的头文件 #define OP_READ1 0xa1 // 器件1地址以及读取操作,0xa1即为1010 0001B #define OP_WRITE1 0xa0 // 器件1地址以…

python文件打包实战技巧

众所周知&#xff0c;python是一种脚本语言&#xff0c;python程序必须在python环境下运行&#xff0c;所以如果想把自己写的程序给别人看的话&#xff0c;就比较麻烦&#xff0c;他需要先配置python环境&#xff0c;对于电脑小白来说这是“要命”的事情。而且如果是客户的话&a…

ubuntu多用户环境dockerbug,卸载重装docker流程

之前不小心误操作删除重装docker&#xff0c;结果删除没成功&#xff0c;更没法重装&#xff0c;每次apt install都会报一个docker错误&#xff0c;虽然不影响软件的常规安装&#xff5e;但是现在还是需要装一个完整docker&#xff0c;还是选择删除一下&#xff0c;重点是关闭服…

多环境及SpringBoot项目部署

1、多环境 2、项目部署上线 原始前端 / 后端项目宝塔Linux容器容器平台 3、前后端联调 4、项目扩展和规划 多环境 程序员鱼皮-参考文章 本地开发&#xff1a;localhost&#xff08;127.0.0.1&#xff09; 多环境&#xff1a;指同一套项目代码在把不同的阶段需要根据实际…

共享单车之数据可视化

文章目录 第1关&#xff1a;绘制地图第2关&#xff1a;绘制流量最高的五条线路的路程图 第1关&#xff1a;绘制地图 任务描述 本关任务&#xff1a;使用JSP在百度地图上绘制一条共享单车起始路程。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 如何创建地…

macos下转换.dmg文件为 .iso .cdr文件的简单方法

为了让镜像文件在mac 和windows平台通用, 所以需要将.dmg格式的镜像文件转换为.iso文件, 转换方法也非常简单, 一行命令即可 hdiutil convert /path/to/example.dmg -format UDTO -o /path/to/example.iso 转换完成后的文件名称默认是 example.iso.cdr 这里直接将.cdr后缀删…

web一些实验代码—— JavaBean与EL标签

实验9&#xff1a; JavaBean与EL标签 使用javaBean和EL&#xff0c;完成注册和注册信息显示。 1、新建RegisterBean&#xff1b; package com.example.weeebbbb.the10;public class RegisterBean {private String user;private String pass;private String repass;private S…

【Transformer】深入理解Transformer模型2——深入认识理解(上)

前言 Transformer模型出自论文&#xff1a;《Attention is All You Need》 2017年 近年来&#xff0c;在自然语言处理领域和图像处理领域&#xff0c;Transformer模型都受到了极为广泛的关注&#xff0c;很多模型中都用到了Transformer或者是Transformer模型的变体&#xff0…

OCR在审核应用落地

本文字数&#xff1a;6686字 预计阅读时间&#xff1a;35分钟 01 背景 1、业务背景 在传统视频审核场景中&#xff0c;审核人员需要对进审视频中的文字内容进行逐一审核&#xff0c;避免在文字上出现敏感词、违禁词或者广告等相关词汇。这种人工审核费时费力&#xff0c;并且由…

【数据结构】双向带头循环链表的实现

前言&#xff1a;在前面我们学习了顺序表、单向链表&#xff0c;今天我们在单链表的基础上进一步来模拟实现一个带头双向链表。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &#x1f448; &#x1f4af;代码仓库:卫卫周大胖的…

50. Pow(x, n)(Leetcode) C++递归实现(超详细)

文章目录 前言一、题目分析二、算法原理1.递归分析2.递归实现 三、代码实现复杂度分析总结 前言 在本文章中&#xff0c;我们将要详细介绍一下Leetcode中第50题&#xff0c; Pow(x, n)的内容 一、题目分析 题目要求很简单&#xff1a;我们模拟实现一个pow函数。 二、算法原理…

IP地址的四大类型:动态IP、固定IP、实体IP、虚拟IP的区别与应用

在网络通信中&#xff0c;IP地址是设备在互联网上唯一标识的关键元素。动态IP、固定IP、实体IP和虚拟IP是四种不同类型的IP地址&#xff0c;它们各自具有独特的特点和应用场景。 1. 动态IP地址&#xff1a; 动态IP地址是由Internet Service Provider&#xff08;ISP&#xff…