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

🔥个人主页 🔥

😈所属专栏😈


每文一诗 💪🏼

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

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


目录

C++运算符重载概念

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

加减乘除运算符重载

赋值运算符重载

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

关系运算符重载

大于号运算符重载

相等运算符重载

全部代码


C++运算符重载概念

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

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

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

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

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

加减乘除运算符重载

  1. 作类成员函数重载
cpp 复制代码
#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;
}

代码解读:

  • 提供默认无参构造函数函数初始化列表

    cpp 复制代码
     human(){};
        human(int a ,int b):m_a(a),m_b(b){
        }
  • 加减乘除运算符重载(成员函数)这里指的是乘法

cpp 复制代码
    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,并将运算后的成员变量更新到该对象并返回。
cpp 复制代码
human h3 = h * h1;

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

cpp 复制代码
std::cout << h3.geta() <<" "<< h3.getb()<<std::endl;

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

  • 输出

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

其他加减除法以此类推。

2.作全局函数重载

cpp 复制代码
#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声明
cpp 复制代码
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;
}

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

cpp 复制代码
    friend human operator*(const human& p2, int val);
cpp 复制代码
human h2 = h * 90;

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

  • 输出

赋值运算符重载

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

cpp 复制代码
#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;
}

代码解读:

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

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

    cpp 复制代码
     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);

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

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

关系运算符重载

大于号运算符重载

cpp 复制代码
#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;
}

代码解读:

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

  • 对于
cpp 复制代码
h > h1

相当于 h.operator>(h1)

  • 对于
cpp 复制代码
h > 12

相当与 operator>(h,12)

  • 输出

相等运算符重载

cpp 复制代码
#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;
}

代码解读:

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

  • 对于
cpp 复制代码
h == h1

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

  • 对于
cpp 复制代码
h == 23

相当于 operator==(h,23)

  • 输出

全部代码

cpp 复制代码
#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;
}

🔥个人主页 🔥

😈所属专栏😈

相关推荐
云和数据.ChenGuang25 分钟前
人工智能 机器学习期末考试题
开发语言·人工智能·python·机器学习·毕业设计
lllsure3 小时前
Python基础语法
开发语言·python
zxctsclrjjjcph5 小时前
【高并发内存池】从零到一的项目之centralcache整体结构设计及核心实现
开发语言·数据结构·c++·链表
zm5 小时前
服务器多客户端连接核心要点(1)
java·开发语言
炯哈哈5 小时前
【上位机——MFC】单文档和多文档视图架构
开发语言·c++·mfc·上位机
FuckPatience5 小时前
关于C#项目中 服务层使用接口的问题
java·开发语言·c#
利刃大大6 小时前
【网络编程】四、守护进程实现 && 前后台作业 && 会话与进程组
linux·网络·c++·网络编程·守护进程
编程轨迹_6 小时前
使用 Spring 和 Redis 创建处理敏感数据的服务
java·开发语言·restful
oioihoii6 小时前
C++23 std::tuple与其他元组式对象的兼容 (P2165R4)
c++·链表·c++23
赵和范6 小时前
C++:书架
开发语言·c++·算法