【C++面向对象】封装(下):探索C++运算符重载设计精髓

news2025/5/20 21:17:31

🔥个人主页 🔥

😈所属专栏😈 


每文一诗  💪🏼

     年年岁岁花相似,岁岁年年人不同 —— 唐/刘希夷《代悲白头翁》

        译文:年年岁岁繁花依旧,岁岁年年看花之人却不相同


目录

C++运算符重载概念

C++运算符重载语法及作用

加减乘除运算符重载

赋值运算符重载

返回值作为引用以实现链式赋值

关系运算符重载

大于号运算符重载

相等运算符重载

全部代码


C++运算符重载概念

        在 C++ 里,运算符重载属于多态的一种表现形式,它允许你为自定义的数据类型重新定义运算符的行为。

运算符重载其实就是对已有的运算符赋予新的功能,使它能够处理自定义类型的对象

C++运算符重载语法及作用

语法:返回类型 operator运算符(参数列表) {}

  1. 提高代码可读性:在处理自定义类型时,使用重载后的运算符能让代码更直观、自然。例如,对于自定义的复数类,你可以重载+运算符,让两个复数相加的操作就像普通数字相加一样简单。
  2. 实现自定义类型的操作:借助运算符重载,你能为自定义类型实现像内置类型那样的操作。比如,对于自定义的矩阵类,你可以重载+-*等运算符,实现矩阵的加减乘运算。
  3. 代码复用与一致性:运算符重载可以复用已有的运算符,使代码更具一致性。对于熟悉内置运算符的开发者来说,重载后的运算符也易于理解和使用。

加减乘除运算符重载

  1. 作类成员函数重载
#include <iostream>

class human
{
public:
    human(){};
    human(int a ,int b):m_a(a),m_b(b){
    }
    //加减乘除运算符重载(成员函数)
    human operator*(const human& h){
        human h2;
        h2.m_a = this->m_a * h.m_a;
        h2.m_b = this->m_b * h.m_b;
        return h2;
    }
   

    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }

private:
    int m_a;
    int m_b;
  
};

int main(int argc, char const *argv[])
{
    human h(10,20);
    human h1(2,10);

    //相当于 h.operator*(h1)
    human h3 = h * h1;
    std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;



    return 0;
}

代码解读:

  • 提供默认无参构造函数函数初始化列表
     human(){};
        human(int a ,int b):m_a(a),m_b(b){
        }
  • 加减乘除运算符重载(成员函数)这里指的是乘法
    human operator*(const human& h){
        human h2;
        h2.m_a = this->m_a * h.m_a;
        h2.m_b = this->m_b * h.m_b;
        return h2;
    }
  1. 这里的参数是指常量引用目的是不使用值传递的方式,防止对数据进行大量的拷贝,常量引用本质使用地址传递,地址通常占有4个字节,程序效率更高
  2. 这里的this指向调用该重载函数的哪个对象。
  3. 栈区重新创建一个对象h,并将运算后的成员变量更新到该对象并返回。
  • human h3 = h * h1;

    这个相当于 h.operator*(h1)

  • std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;

    因为成员变量m_a和m_b时私有变量,不能在类外访问,所以在类内使用函数来访问。

  • 输出

这样就实现了类型为human的变量使用运算符来进行运算,20 = 10 *2 ;200 = 20*10

其他加减除法以此类推。

2.作全局函数重载

#include <iostream>

class human
{
    friend human operator*(const human& p2, int val);
public:
    human(){};
    human(int a ,int b):m_a(a),m_b(b){
    }
    //加减乘除运算符重载(成员函数)
    human operator*(const human& h){
        human h2;
        h2.m_a = this->m_a * h.m_a;
        h2.m_b = this->m_b * h.m_b;
        return h2;
    }


    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }

private:
    int m_a;
    int m_b;
  
};
// 加减乘除运算符重载(全局函数)访问私有成员需要加friend声明
human operator*(const human& p2, int val)
{
    human temp;
    temp.m_a = p2.m_a *val;
    temp.m_b = p2.m_b * val;
   
    return temp;
}

int main(int argc, char const *argv[])
{
    human h(10,20);
    human h1(2,10);

    //相当与 operator*(h,90)
    human h2 = h * 90;
    //相当于 h.operator*(h1)
    human h3 = h * h1;

    std::cout << h2.geta() <<" "<< h2.getb()<<std::endl;
    std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;

    return 0;
}

代码解读:

  •  加减乘除运算符重载(全局函数)访问私有成员需要加friend声明
human operator*(const human& p2, int val)
{
    human temp;
    temp.m_a = p2.m_a *val;
    temp.m_b = p2.m_b * val;
   
    return temp;
}

        该函数在类外定义,在类外定义的函数不能访问类内的私有变量,但是可以通过友元函数的方法来让类外定义的全局函数访问类内的私有变量。即

    friend human operator*(const human& p2, int val);
  • human h2 = h * 90;

     相当与 operator*(h,90)调用的是全局函数。

  • 输出

赋值运算符重载

返回值作为引用以实现链式赋值

#include <iostream>

class human
{

public:
    human(){};
    human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){
    }
    //赋值运算符重载
    human& operator=(const human& h){
        if(this != &h){
            if(m_c != nullptr){
                delete m_c;
                m_c = nullptr;
            }
        }
        m_c = new int(*h.m_c);
        return *this;
    }

    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }
    int getc(){
        return *this->m_c;
    }
private:
    int m_a;
    int m_b;
    int* m_c;
  
};


int main(int argc, char const *argv[])
{
    human h(10,20,12);
    human h1(2,10,34);
    human h2(22,10,4);

    h = h1 = h2;
    std::cout <<h.getc()<<std::endl;

    return 0;
}

 代码解读:

  • 函数初始化列表来初始化成员变量

        human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){
        }
  • 赋值运算符重载

     human& operator=(const human& h){
            if(this != &h){
                if(m_c != nullptr){
                    delete m_c;
                    m_c = nullptr;
                }
            }
            m_c = new int(*h.m_c);
            return *this;
        }

          首先使用this来判断调用该函数的对象是否和传入的对象是同一块内存,接着在判断调用该成员函数的对象中的成员变量m_c是否不为空,不为空则释放内存,再置为空。

两个对象不是同一块内存(this != &h)需要delete,再重新开辟内存。

  • 这样作的目的是用于:如果对一个成员变量是指针的对象,将该指针指向的值进行修改时,需要先释放调用该重载函数的对象中指针变量,再为空,然后在m_c = new int(*h.m_c);重新开辟一块内存,内存的值是参数中对象的那个值。

  • 原因:若不释放这块内存,在赋值操作完成后,原来的内存就会变成无法访问的 “孤儿” 内存,程序无法再释放它,从而造成内存泄漏。执行 delete m_c; 就能正确释放这块内存,让系统可以重新使用它。

两个对象是同一块内存(this == &h)不需要delete。

  • 原因:当两个对象是统一块内存时,m_c这个指针变量指向的值是一样的,如果对其执行 delete m_c,那么在后面m_c = new int(*h.m_c);时使用*h.m_c时是非法的,因为这块内存已经被释放掉了,不能访问。

为什么要m_c = new int(*h.m_c);

  • 原因:编译器默认提供的是浅拷贝,对于一个含有指针变量的类中,浅拷贝会对这块内存多次释放,是不合法的,所以需要执行深拷贝来使得两个对象中的指针变量指向的值相同,但指针的值不同(地址不同)
  • 有关【C++面向对象】封装(上):探寻构造函数的幽微之境-CSDN博客深拷贝,浅拷贝【C++面向对象】封装(上):探寻构造函数的幽微之境-CSDN博客

为什么return *this;返回值类型是human&引用。

  • 原因:this指向调用该成员函数的那个对象,而*this是指的该对象,而返回值是human&引用是为了实现链式调用,而返回值是human不能实现链式赋值,因为他返回的是该对象的拷贝。

关系运算符重载

大于号运算符重载

#include <iostream>

class human
{
    friend bool operator>(const human& h1,int val);
public:
    human(){};
    human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){
    }

    //关系运算符重载
    bool operator>(const human& h1){
        if(this->m_a > h1.m_a && this->m_b > h1.m_b)
        return true;
        else
        return false;
    }
    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }
    int getc(){
        return *this->m_c;
    }
private:
    int m_a;
    int m_b;
    int* m_c;
  
};

//关系运算符重载(全局函数)访问私有成员需要加friend声明
bool operator>(const human& h1,int val){
    if(val< h1.m_a && val < h1.m_b)
    return true;
    else
    return false;
}
int main(int argc, char const *argv[])
{
    human h(10,20,12);
    human h1(2,10,34);

    //相当于 h.operator>(h1)
    if(h > h1)
    std::cout<<"h>h1"<<std::endl;
    else
    std::cout<<"h<h1"<<std::endl;
     //相当与 operator>(h,12)
    if(h > 12)
    std::cout<<"h>12"<<std::endl;
    else
    std::cout<<"h<12"<<std::endl;


    return 0;
}

 代码解读:

上段代码分别用成员函数和全局函数的方法来实现对自定义类型的判断

  • 对于
h > h1

相当于 h.operator>(h1)

  • 对于
h > 12

相当与 operator>(h,12)

  • 输出

相等运算符重载

#include <iostream>

class human
{
    friend bool operator==(const human& h1,int val);
public:
    human(){};
    human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){
    }

    //关系运算符重载
    bool operator==(const human& h1){
        if(this->m_a == h1.m_a && this->m_b == h1.m_b)
        return true;
        else
        return false;
    }


    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }
    int getc(){
        return *this->m_c;
    }
private:
    int m_a;
    int m_b;
    int* m_c;
  
};

 //关系运算符重载(全局函数)访问私有成员需要加friend声明
bool operator==(const human& h1,int val){
    if(val == h1.m_a)
    return true;
    else
    return false;
}

int main(int argc, char const *argv[])
{
    human h(10,20,12);
    human h1(2,10,34);

    //相当于 h.operator==(h1)
    if(h == h1)
    std::cout<<"二者相等"<<std::endl;
    else
    std::cout<<"二者不等"<<std::endl;
     //相当与 operator==(h,23)
    if(h == 23)
    std::cout<<"二者相等"<<std::endl;
    else
    std::cout<<"二者不等"<<std::endl;



    return 0;
}

  代码解读:

上段代码分别用成员函数和全局函数的方法来实现对自定义类型的相等判断

  • 对于
h == h1

相当于相当于 h.operator==(h1)

  • 对于
h == 23

相当于 operator==(h,23)

  • 输出

全部代码

#include <iostream>

class human
{
    friend human operator*(const human& p2, int val);
    friend bool operator==(const human& h1,int val);
    friend bool operator>(const human& h1,int val);
public:
    human(){};
    human(int a ,int b,int c):m_a(a),m_b(b),m_c(new int(c)){
    }
    //加减乘除运算符重载(成员函数)
    human operator*(const human& h){
        human h2;
        h2.m_a = this->m_a * h.m_a;
        h2.m_b = this->m_b * h.m_b;
        return h2;
    }
    //关系运算符重载
    bool operator==(const human& h1){
        if(this->m_a == h1.m_a && this->m_b == h1.m_b)
        return true;
        else
        return false;
    }
    //关系运算符重载
    bool operator>(const human& h1){
        if(this->m_a > h1.m_a && this->m_b > h1.m_b)
        return true;
        else
        return false;
    }
    //赋值运算符重载
    human& operator=(const human& h){
        if(this != &h){
            if(m_c != nullptr){
                delete m_c;
                m_c = nullptr;
            }
        }
        m_c = new int(*h.m_c);
        return *this;
    }

    int geta(){
        return this->m_a;
    }
    int getb(){
        return this->m_b;
    }
    int getc(){
        return *this->m_c;
    }
private:
    int m_a;
    int m_b;
    int* m_c;
  
};
// 加减乘除运算符重载(全局函数)访问私有成员需要加friend声明
human operator*(const human& p2, int val)
{
    human temp;
    temp.m_a = p2.m_a *val;
    temp.m_b = p2.m_b * val;
   
    return temp;
}
 //关系运算符重载(全局函数)访问私有成员需要加friend声明
bool operator==(const human& h1,int val){
    if(val == h1.m_a)
    return true;
    else
    return false;
}
//关系运算符重载(全局函数)访问私有成员需要加friend声明
bool operator>(const human& h1,int val){
    if(val< h1.m_a && val < h1.m_b)
    return true;
    else
    return false;
}
int main(int argc, char const *argv[])
{
    human h(10,20,12);
    human h1(2,10,34);

    //相当与 operator*(h,90)
    human h2 = h * 90;
    //相当于 h.operator*(h1)
    human h3 = h * h1;

    //相当于 h.operator==(h1)
    if(h == h1)
    std::cout<<"二者相等"<<std::endl;
    else
    std::cout<<"二者不等"<<std::endl;
     //相当与 operator==(h,23)
    if(h == 23)
    std::cout<<"二者相等"<<std::endl;
    else
    std::cout<<"二者不等"<<std::endl;

    //相当于 h.operator>(h1)
    if(h > h1)
    std::cout<<"h>h1"<<std::endl;
    else
    std::cout<<"h<h1"<<std::endl;
     //相当与 operator>(h,12)
    if(h > 12)
    std::cout<<"h>12"<<std::endl;
    else
    std::cout<<"h<12"<<std::endl;

    std::cout << h2.geta() <<" "<< h2.getb()<<std::endl;
    std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;

    h = h1;
    std::cout <<h.getc()<<std::endl;

    return 0;
}

 🔥个人主页 🔥

😈所属专栏😈 

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

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

相关文章

JVM初探——走进类加载机制|三大特性 | 打破双亲委派SPI机制详解

目录 JVM是什么&#xff1f; 类加载机制 Class装载到JVM的过程 装载&#xff08;load&#xff09;——查找和导入class文件 链接&#xff08;link&#xff09;——验证、准备、解析 验证&#xff08;verify&#xff09;——保证加载类的正确性 准备&#xff08;Prepare&…

UML-饮料自助销售系统(无法找零)序列图

一、题目&#xff1a; 在饮料自动销售系统中&#xff0c;顾客选择想要的饮料。系统提示需要投入的金额&#xff0c;顾客从机器的前端钱币口投入钱币&#xff0c;钱币到达钱币记录仪&#xff0c;记录仪更新自己的选择。正常时记录仪通知分配器分发饮料到机器前端&#xff0c;但可…

爬虫利器SpiderTools谷歌插件教程v1.0.0!!!web端JavaScript环境检测!!!

SpiderTools谷歌插件教程v1.0.0 一、SpiderTools简介二、下载通道三、插件介绍四、插件使用五、工具函数使用 一、SpiderTools简介 SpiderTools主要用于检测和监控网页的JavaScript运行环境。该插件可以帮助开发者更好地查看网页运行环境&#xff0c;特别是在处理复杂的前端环…

计算机视觉算法实战——基于YOLOv8的农田智能虫情测报灯害虫种类识别系统开发指南

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 一、智能虫情监测领域概述 1.1 农业虫害防治现状 全球每年因虫害造成的粮食损失达20%-40%&#xff0c;我…

14-算法打卡-哈希表-基本概念-第十四天

1 基本概念 1.1 哈希表 百度百科解释&#xff1a; 散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据关键码值(Key value)而直接进行访问的数据结构。也就是说&#xff0c;它通过把关键码值映射到表中一个位置来访问记录&#xff0c;以加快…

第十六届蓝桥杯大赛软件赛省赛 C++ 大学 B 组 部分题解

赛时参加的是Python组&#xff0c;这是赛后写的题解&#xff0c;还有两题暂时还不会&#xff0c;待更新 题目链接题目列表 - 洛谷 | 计算机科学教育新生态 A 移动距离 答案&#xff1a;1576 C 可分解的正整数 Python3 import itertools from functools import cmp_to_ke…

英文查重的时候参考文献显示重复是怎么回事?

像上图这样参考文献部分有颜色的情况&#xff0c;是属于参考文献没有排除干净的问题。 如何解决这样的问题&#xff1f; 首先第一步&#xff0c;先确认该报告是不是排除参考文献的版本&#xff1b; 第二步&#xff0c;如果是排除参考文献的版本&#xff0c;且参考文献仍然有…

八股文---MySQl(3)

目录 12.事务的特性是什么&#xff1f;可以详细说一下吗&#xff1f; 回答 13并发事务带来哪些问题&#xff1f;怎么解决这些问题呢&#xff1f;MySQL的默认隔离级别是&#xff1f; 脏读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 不可重复读&#xff1a;一个…

基于labview的钢琴程序设计

部分程序如下 按照上图子vi更改输出频率即可 若需完整程序可以联系我

基于CNN+ViT的蔬果图像分类实验

本文只是做一个简单融合的实验&#xff0c;没有任何新颖&#xff0c;大家看看就行了。 1.数据集 本文所采用的数据集为Fruit-360 果蔬图像数据集&#xff0c;该数据集由 Horea Mureșan 等人整理并发布于 GitHub&#xff08;项目地址&#xff1a;Horea94/Fruit-Images-Datase…

【虚幻C++笔记】接口

目录 概述创建接口 概述 简单的说&#xff0c;接口提供一组公共的方法&#xff0c;不同的对象中继承这些方法后可以有不同的具体实现。任何使用接口的类都必须实现这些接口。实现解耦解决多继承的问题 创建接口 // Fill out your copyright notice in the Description page o…

【MCP】第一篇:MCP协议深度解析——大模型时代的“神经连接层“架构揭秘

【MCP】第一篇&#xff1a;MCP协议深度解析——大模型时代的"神经连接层"架构揭秘 一、什么是MCP&#xff1f;二、为什么需要MCP&#xff1f;三、MCP的架构四、MCP与AI交互的原理4.1 ReAct&#xff08;Reasoning Acting&#xff09;模式4.2 Function Calling 模式 五…

实时模式下 libaom 与 x264 编码对比实验

前沿 理论基础&#xff1a;在相同视频质量下&#xff0c;AV1的压缩率比H.264高约30%-50%。实时模式&#xff1a;视频编码中的实时模式&#xff0c;其核心目标是平衡编码效率与延迟要求&#xff0c;尤其在视频会议、直播、实时通信等场景中至关重要。 低延迟要求&#xff1a;编…

学习海康VisionMaster之矩形检测

这几天太忙了&#xff0c;好几天没有学习了&#xff0c;今天终于空下来了&#xff0c;继续学习之路吧。 一&#xff1a;进一步学习了 今天学习下VisionMaster中的矩形检测&#xff0c;这个一开始我以为是形态学方面的检测&#xff0c;实际操作下来其实还是边缘直线的衍生应用&…

C Primer Plus 第6版 编程练习——第3章

1、通过试验&#xff08;即编写带有此类问题的程序&#xff09;观察系统如何处理整数上道、浮占数上溢和浮点数下溢的 int main(int argc, char** argv) {int intMax 2147483647;float floatMax 3.402823466e38f;float floatMin -3.402823466e38f;printf("intMax:%d, …

十倍开发效率 - IDEA插件之 Mybatis Log Free

提高效率不是为了完成更多任务&#xff0c;而是为了有充足的时间摸鱼 快速体验 MyBatis Log Free 支持打印执行的 SQL&#xff08;完整的SQL&#xff0c;没有占位符的&#xff09;。 没有使用 MyBatis Log Free 的开启日志打印是这样的&#xff1a; 用了 MyBatis Log Free 后…

手动安装 VMware Tools 并设置虚拟机共享 Windows 文件夹

前言&#xff1a;在当今数字化的工作环境中&#xff0c;虚拟机技术为我们提供了强大的灵活性和便利性。VMware 作为虚拟化领域的佼佼者&#xff0c;其虚拟机软件被广泛应用于开发、测试和日常工作中。然而&#xff0c;许多用户在使用 VMware 虚拟机时&#xff0c;会遇到一个常见…

(免费)flask调用讯飞星火AI,实现websocket

本文章可借鉴学习&#xff0c;不可直接盗用 接入ai要获取ID&#xff0c;Secret&#xff0c;Key&#xff0c;和接口地址&#xff0c;由于我们服务接口类型是websocket&#xff0c;所以要获取相应的接口地址。&#xff08;千万不要复制粘贴到http的了&#xff09; 还要获取doma…

2021-11-09 C++三位数平方含有该数

缘由求解&#xff0c;运算函数&#xff0c;哪位大神教一下-编程语言-CSDN问答 void 三位数平方含有该数() {//缘由https://ask.csdn.net/questions/7560152?spm1005.2025.3001.5141int a 100, aa 1000, f 0;while (a < aa){f a*a;while (f > a)if ((f - a) % aa)f …

StarRocks Community Monthly Newsletter (Mar)

版本动态 3.4.1 版本更新 核心功能升级 数据安全与权限管控 支持「安全视图」功能&#xff0c;严格管控视图查询权限 MySQL协议连接支持SSL认证&#xff0c;保障数据传输安全 存算分离架构增强 支持自动创建Snapshot&#xff08;集群恢复更便捷&#xff09; Storage Volu…