【C++】类和对象之运算符重载(三)

简介: 【C++】类和对象之运算符重载(三)

前言:在前面我们知道在类和对象中有六个默认成员函数,并学习了其中三个构造函数、析构函数、拷贝构造函数,今天我们将进一步的学习.赋值运算符重载。

d6dc0126edd141a985d72de501ef756b.jpg


运算符重载

运算符重载的概念:C++运算符重载是指在C++中可以自定义操作符的含义和行为。通过运算符重载,可以使用相同的操作符来执行不同类的对象的操作,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

C++中可以重载的运算符有:

  • 算术运算符(+、-、*、/、%等)
  • 关系运算符(==、!=、<、>、<=、>=等)
  • 逻辑运算符(!、&&、||等)
  • 位运算符(&、|、^等)
  • 赋值运算符(=、+=、-=等)
  • 自增自减运算符(++、–等)
  • 下标运算符([])
  • 函数调用运算符(())

要重载一个运算符,需要使用运算符关键字operator,以及重载函数的名称和参数。重载函数可以作为类的成员函数,也可以作为全局函数


函数原型返回值类型 operator操作符(参数列表)

格式如下:

<返回类型说明符> operator <运算符符号>(<参数表>)
{
 
     <函数体>
 
}

注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。

全局的operator

以下是一个全局重载等于运算符的示例:

class Date
{
public:
    Date(int year = 2024, int month = 2, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << "year = " << this->_year << " month = " << this->_month << " day = " << this->_day << endl;

    }
public://这里一定得是共有,不然外部无法访问
    int _year;
    int _month;
    int _day;
};

bool operator==(const Date& s1,const Date& s2)
{
    return s1._year == s2._year &&
        s1._month == s2._month &&
        s1._day == s2._day;
}

int main()
{
    Date d1;
    Date d2(2024, 2, 4);
    Date d3(d2);
    if (d1 == d2)//判断d1和d2是否相等
    {
        cout << "d1 == d2" << endl;
    }
    else
    {
        cout << "d1 != d2" << endl;
    }
    if (d2 == d3)
    {
        cout << "d2 == d3" << endl;
    }
    else
    {
        cout << "d3 != d2" << endl;
    }
    return 0;
}

这里作者强调一下重载函数接收参数时候为什么要加上const修饰,因为我们在引用的时候,如果不加上const,就如下面这个例子一样,有的人写代码时候可能没有注意,一不小心就把原本的对象的值给修改了,所以我们接收参数的时候通常加上const对它进行修饰。

class Date
{
public:
    Date(int year = 2024, int month = 2, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << "year = " << this->_year << " month = " << this->_month << " day = " << this->_day << endl;

    }
public://这里一定得是共有,不然外部无法访问
    int _year;
    int _month;
    int _day;
};
void operator+(Date& s1,Date& s2)//重载
{
    s2._year = s1._year++;
}

int main()
{
    Date d1;
    Date d2(2024, 2, 4);
    cout << "重载前" << endl;
    cout << "d1:";
    d1.Print();
    cout << "d2:";
    d2.Print();
    d2 + d1;
    cout << "重载后" << endl;
    cout << "d1:";
    d1.Print();
    cout << "d2:";
    d2.Print();
    return 0;
}

局部的operator

当然了光说不做,等于白说,以下是一个局部重载等于运算符的示例:

#include <iostream>
#include <stdbool.h>
using namspace std;
class Date
{
public:
    Date(int year = 2024,int month = 2,int day = 1)//初始化
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << "year = " << this->_year << " month = " << this->_month << " day = " << this->_day << endl;

    }   
    bool operator==(const Date& s1)//在类中成员函数的第一个参数为隐藏的this,因此我们只需要一个参数
    {
        return _year == s1._year &&
            _month == s1._month &&
            _day == s1._day;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    Date d2(2024, 2, 4);
    Date d3(d2);
    if (d1 == d2)//判断d1和d2是否相等
    {
        cout << "d1 == d2" << endl;
    }
    else
    {
        cout << "d1 != d2" << endl;
    }
    if (d2 == d3)
    {
        cout << "d2 == d3" << endl;
    }
    else
    {
        cout << "d3 != d2" << endl;
    }
  return 0;
}

这里很多人会很疑惑,为什么你这里只有一个参数,你这一个参数怎么比较两个数是不是相等?这里作者来给大家解释一下,其实本质上这里有一个隐式的this指针我们在前面也提到过,如果不懂什么是this指针的可以去看看博主前面的文章。


别看这里可以赋值,但是我们思考一下,能不能连续赋值呢?

d1 = d2 = d3;//如果我们要这样赋值呢?

怎么会出现下面这个情况?我们不是赋值了嘛?

代码刨析

  1. 我们之所以在两个数的时候能够赋值,是因为this指针在函数内部就对d2进行了修改。
  2. 在连续赋值的时候,我们该重载函数返回的是void类型,相当于我们在对d1赋值的时候是传递了一个void类型的数据过去,void类型又怎么可以赋值呢?因此我们要想实现连续赋值这里肯定是不能用void作为返回类型。

那么我们又如何解决连续赋值存在的问题呢?

. 在前面我们知道了是返回值的问题,那么我们就可以通过对返回值的修改来帮助我们解决

4. 返回什么呢?这里我们可以通过返回this*,此时这里的返回值等价于返回了d2这个对象,因此可以通过返回引用来解决返回值的问题

class Date
{
public:
    Date(int year = 2024, int month = 2, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << "year = " << this->_year << " month = " << this->_month << " day = " << this->_day << endl;

    }
    Date& operator=(const Date& s1)
    {
        _year = s1._year;
        _month = s1._month;
        _day = s1._day;
        return *this;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2003,9,22);
    Date d2(2002,9,26);
    Date d3(0, 0, 0);
    cout << "重载前" << endl;
    d1.Print();
    d2.Print();
    d3.Print();
    d1 = d2 = d3;
    cout << "重载后" << endl;
    d1.Print();
    d2.Print();
    d3.Print();   
    return 0;
}


显示重载

显示赋值操作符重载:用的比较少这里作者就偷懒提一下

class MyClass {
public:
    MyClass& operator=(const MyClass& other) {//显示重载
        // 在这里实现赋值操作
        return *this;
    }
};

int main() {
    MyClass obj1;
    MyClass obj2;
    obj2 = obj1; // 调用赋值操作符重载
    return 0;
}

注意事项

在C++中,运算符重载是一种强大的特性,它可以让我们自定义类类型的行为,使其像内置类型一样使用运算符。然而,运算符重载也需要遵循一些注意事项,以确保正确和安全地使用。

以下是运算符重载的一些注意事项:

  1. 只能重载已存在的运算符:C++只允许重载已存在的运算符,而不允许创建新的运算符。例如,可以重载"+", “-”, "*“等运算符,但不能重载”%%“或”**"等新的运算符。
  2. 不改变运算符的优先级:运算符重载不会改变运算符的优先级和结合性。例如,重载"+"运算符不会改变它的加法操作的优先级和结合性。
  3. 重载运算符需要至少一个操作数是用户定义的类型:为了重载运算符,至少需要一个操作数是用户定义的类型(自定义类),因此重载的运算符不能用于内置类型的操作。
  4. 通常情况下,重载运算符应该作为类的成员函数:通常情况下,应该将运算符重载函数声明为类的成员函数。这样可以使其在类的对象上直接调用,并享受到类的私有成员的访问权限。然而,也可以将运算符重载函数声明为友元函数,以便访问类的私有成员。
  5. 一些运算符只能重载为成员函数:一些运算符(例如赋值运算符和下标运算符)只能作为类的成员函数进行重载。这是因为它们对操作数的顺序有特定的要求,只能将类的对象作为左操作数。
  6. 谨慎使用运算符重载:运算符重载是一种很强大的特性,但也容易被滥用。在重载运算符时,要确保其行为符合直觉,不会给其他开发者带来困惑。建议只在有必要时才使用运算符重载,避免滥用。
  7. 重载运算符的返回类型应该符合预期:重载运算符的返回类型应该符合预期的语义和行为。例如,重载"+="运算符时,返回的是左操作数的引用,以实现链式赋值的语法。

需要注意的是,虽然运算符重载可以更灵活地使用类对象,但也需要谨慎使用,以避免混淆和错误的行为。在重载运算符时,应该遵循一些通用的原则和最佳实践,确保代码的可读性、可维护性和安全性。


好啦,今天的内容就到这里啦,下期内容预告类和对象(四)日期类的实现

结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


相关文章
|
8天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
3691 16
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
16天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3605 13
|
10天前
|
人工智能 自然语言处理 供应链
|
12天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2997 7
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
19天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3729 25
|
10天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
1471 3
|
3天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
502 0