C++面向对象学习笔记五

本文主要讲解运算符重载,由于白鳯大佬没有具体讲解,所以本文自行补充了运算符重载的相关知识
目录

文章目录

前言

运算符重载

加号运算符重载

左移运算符重载

递增运算符重载

总结


前言

本文主要对于运算符重载进行探讨,分别对于成员函数重载和全局函数重载(友元函数重载)进行讨论。


运算符重载

运算符重载是C++中的一项强大功能,它允许您为自定义的类或结构体定义特定的行为,以响应与内置类型相似的操作符。通过重载运算符,您可以实现自定义类型之间的数学运算、比较、位操作等。

运算符重载使用operator关键字后跟要重载的运算符来实现。例如,+表示加法运算符,-表示减法运算符等。

运算符重载一般分为成员函数重载和全局函数重载

以下是一些常见的需要进行运算符重载的情况:

  1. 算术运算符:例如 +, -, *, /, %
  2. 比较运算符:例如 ==, !=, <, >, <=, >=
  3. 赋值运算符:例如 =, +=, -=, *=, /=
  4. 位操作运算符:例如 &, |, ^
  5. 下标操作符:[]
  6. 函数调用操作符:()

对于每个需要进行重载的运算符,您可以根据需求定义适当的成员函数或非成员函数。成员函数形式在对象本身上调用该操作,而非成员函数形式将两个对象作为参数传递。

请注意,在进行运算符重载时,请遵循一些最佳实践和规则:

  1. 不要改变原始对象的状态(如果不是必要的)。
  2. 避免创建歧义或混乱的重载操作。
  3. 考虑使用友元函数来实现某些运算符重载,以便访问私有成员。

运算符重载是C++语言中的一项强大功能,可以提高代码的可读性和表达能力。

加号运算符重载

加号运算符(+)可以在C++中进行重载,使其适用于自定义类型的对象。要重载加号运算符,您可以使用成员函数或非成员函数的形式。

成员函数形式:本质为 p3 = p1.operator+(p2)

cpp 复制代码
class MyClass {
public:
    MyClass operator+(MyClass& other) {
        // 在这里实现加法操作,并返回结果
    }
};
cpp 复制代码
#include <iostream>

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }

    void display() const {
        std::cout << "(" << real << " + " << imag << "i)" << std::endl;
    }
};

int main() {
    Complex c1(2.5, 3.7);
    Complex c2(1.8, -2.9);

    Complex sum = c1 + c2; // 使用重载的加号运算符

    sum.display(); // 输出:(4.3 + 0.8i)

   return 0;
}

全局函数形式:(友元函数访问私有成员)本质为 p3 = operator+(p1,p2)

cpp 复制代码
class MyClass {
public:
    
};
 MyClass operator+(const MyClass& obj1, const MyClass& obj2) {
        // 在这里实现加法操作,并返回结果
    }
cpp 复制代码
#include <iostream>

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

    // 声明友元函数以便访问私有成员
    friend Complex operator+(const Complex& c1, const Complex& c2);

    void display() const {
        std::cout << "(" << real << " + " << imag << "i)" << std::endl;
    }
};

Complex operator+(const Complex& c1, const Complex& c2) {
    return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

int main() {
    Complex c1(2.5, 3.7);
    Complex c2(1.8, -2.9);

    Complex sum = c1 + c2; // 使用重载的加号运算符

    sum.display(); // 输出:(4.3 + 0.8i)

   return 0;
}

俩个代码实现内容一样,主要一个是成员函数,一个全局函数,全局函数需要成为友元函数来访问类的私有数据成员。

同时运算符重载也可以发生函数重载

左移运算符重载

如果我们有一个person类,建立一个对象p,当我们想直接使用cout<<p<<endl;来输出对象p中的内容似乎并不能直接实现,C++并不认识这个类,也不知道如何输出。

这里我们就可以使用左移运算符重载了,与上面的加号运算符一样,左移运算符同样是以operato<<形式实现的,这里我们仍然可以分为成员函数重载和全局函数重载来分别实现一下。

当我们按照成员函数来写时,就会发现一个问题,首先你不能给自己传入p,即p.operator<<(p),然后我们再使用p.operator<<(cout),而这样简化的版本就是p<<cout,与我们想要的cout<<p相反了,所以我们不使用成员函数来实现左移运算符,而使用全局函数。

cpp 复制代码
void operator<<(cout)
{
//简化完事 p << cout
}

如果用全局函数首先要知道的事,cout是输出流对象,即ostream对象

使用operator<<(ostream &cout,person &p)进行函数重载,简化完事cout<<p

至于为什么不用void空值,而是ostream &,是因为,当你主函数使用函数重载输出后,如果返回的事空值,就不能继续追加输出,例如<<endl;补上换行,因为cout后面一直能连续使用<<是链式编程,需要返回的还是cout,即返回ostream输出流。

cpp 复制代码
class preson 
{
private: 
string p_name;
int p_age;
public:
friend ostream & operator<<(ostream &cout,person &p);
}
ostream & operator<<(ostream &cout,person &p)
{
    cout<<"p_name"<<p.p_name<<"p_age"<<p._age<<endl;
}

递增运算符重载

递增运算符重载,即要对++进行运算符重载

跟C++中的++a,a++一样,递增运算符重载也要分为前置递增和后置递增的重载

解决下述代码中几个重点问题

1、函数重载的返回类型就是自己建立的Integer类型是因为,如果有个对象num,当你想要实现对num++或者++num直接输出,类似于a=1;cout<<a++<<endl;的操作时,你需要返回Integer类型,否则返回空值是没有输出的

2、为什么前置递增返回值类型引用了,而后置递增返回值类型没有引用。

后置传递如果使用引用,那么值就错了,要返回递增前的值

这个主要是了解++运算符实现的本质

a=1;

cout<<++(++a)<<endl; 这个是对的,说明前置运算符计算本质是引用,对一个数修改

cout<<(a++)++<<endl; 这个是错的,说明后置运算符计算本质是值传递,无法二次修改

3、下述代码偷懒了,应该演示一下++num,num++的输出,而不是使用成员函数getValue来实现,其实只要将左移运算符重载一下就可以了,按照已讲过的方法实现即可

cpp 复制代码
#include <iostream>
using namespace std;

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

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

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

    int getValue() const {
        return value;
    }
};

int main() {
    Integer num1(5);

    cout << "初始值: " << num1.getValue() << endl;

    // 前置递增
    ++num1;
    cout << "前置递增后的值: " << num1.getValue() << endl;

     // 后置递增
     Integer num2 = num1++;
     cout << "后置递增后的值: " << num2.getValue() << endl;
     cout << "num1当前的值: " << num1.getValue() << endl;

     return 0;
}

总结

本文主要对运算符重载进行了探讨,主要讲述了运算符重载分为成员函数重载和全局函数重载(友元函数重载)这样的操作,并举例加号,左移以及递增运算符的重载方法和一些注意事项。

通过上述的讲解,可以实现更多的运算法重载的方法,当然还有很多运算符重载值得我们探讨,本文讲述的内容也比较有限。

推荐学习博客 https://xxetb.xetslk.com/s/4GgGz6

相关推荐
武子康30 分钟前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
CXDNW39 分钟前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙39 分钟前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
ssf-yasuo1 小时前
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
论文阅读·笔记·prompt
As977_1 小时前
前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)
前端·css·学习
ajsbxi1 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
Rattenking1 小时前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
TeYiToKu1 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
dsywws1 小时前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
道法自然04021 小时前
Ethernet 系列(8)-- 基础学习::ARP
网络·学习·智能路由器