首页 > 其他分享 >关系运算符重载,以及在关系运算符重载发现的函数参数什么时候需要用引用

关系运算符重载,以及在关系运算符重载发现的函数参数什么时候需要用引用

时间:2022-09-22 12:22:29浏览次数:58  
标签:函数参数 Age 运算符 Person 引用 重载 拷贝

在学习关系运算符重载的时候,看见重载函数中的函数参数使用的是引用类型,于是在思考为什么需要用引用,而不是非引用,例如:

引用格式:bool operator==(Person & p)

非引用格式:bool operator==(Person p)

思考这个问题?

条件:Person对象中存在new的成员属性

 

思考这个问题之前,先看一下学习关系运算符重载的代码:

class Person
{
public:
    //年龄的指针,初始化是用new来创建的,放在堆区,因此需要注意深浅拷贝问题
    int *m_Age;

    Person(int age){
        m_Age = new int(age);
    }

    Person& operator=(Person &p){
        // 如果m_Age在堆中占内存,则需要delete堆中的内存
        if (m_Age != NULL){
            delete m_Age;
            m_Age = NULL;
        }
        m_Age = new int(*p.m_Age);

        return *this;
    }
    ~Person(){
        // 如果m_Age还在堆中占内存,则需要delete
        if (m_Age != NULL){
            delete m_Age;
            m_Age = NULL;
        }

        cout << "析构函数" << endl;
    }
    bool operator==(Person& p){
        if (*this->m_Age == *p.m_Age){
            return true;
        }
        return false;
    }

    // 这里必须函数的参数必须使用引用,否则会报错!
    // 因为如果不使用引用的话,则会使用浅拷贝,导致析构的时候出错函数
    bool operator!=(Person& p){
        if (*this->m_Age != *p.m_Age){
            return true;
        }
        return false;
    }
};


void test01()
{
    Person p1(18);

    Person p2(20);

    Person p3(30);

    p3 = p2 = p1; //赋值操作

    cout << "p1的年龄为:" << *p1.m_Age << endl;

    cout << "p2的年龄为:" << *p2.m_Age << endl;

    cout << "p3的年龄为:" << *p3.m_Age << endl;

    // 如果重载==时,不使用引用,则会delete p2中new的m_Age
    cout << boolalpha << (p3 == p2) << endl;
    //此时p2的m_Age为NULL

    cout << *p2.m_Age << endl;

    cout << &p1.m_Age << "  " << &p2.m_Age << "   " << &p3.m_Age << endl;

    cout << boolalpha << (p2 != p3) << endl;

    cout << "再次结束" << endl;

    //而且我还发现,析构函数的顺序,恰好与创建对象的顺序相反!
}

int main() {

    test01();

    //int a = 10;
    //int b = 20;
    //int c = 30;

    //c = b = a;
    //cout << "a = " << a << endl;
    //cout << "b = " << b << endl;
    //cout << "c = " << c << endl;

    return 0;
}

上述代码是没问题的

 

于是回到最开始的思考,如果把重载运算符函数的参数变为非引用格式会是什么结果呢?

Text(686,0x10aaef600) malloc: *** error for object 0x600002068050: pointer being freed was not allocated
Text(686,0x10aaef600) malloc: *** set a breakpoint in malloc_error_break to debug

直接报错,显示被释放的指针没有被分配内存

因此考虑,为什么报错呢?

思考过程:

1、释放指针是什么意思?在Person中只有m_Age是需要自己手动释放的,那问题肯定是出在这里!

2、为什么释放的指针没有被分配内存?于是开始排查主函数中是p1,p2,p3中谁的m_Age被释放了?通过在析构函数中打印发现原来是真的是重载函数出的问题!

3、开始思考为什么使用引用参数没事,非引用参数就会被释放?

浅拷贝和深拷贝问题!

使用非引用参数的话,在调用函数的时候会创建一个临时浅拷贝的临时对象,在函数执行结束之后会析构掉这个临时的对象,由于浅拷贝因此会把之前p1或p2或p3中的m_Age析构掉,因此问题就出现在这里!

如果使用的是引用,则不会出现创建临时对象浅拷贝的问题!

 

问题到这就算是解决了!

但是我还在思考,为什么使用引用就不会呢?是因为引用是对象的别名,函数调用完之后只是会删除别名所占的空间,由于原来对象的生命周期还没结束,因此不会被删除?这么理解是否正确呢?还是有更好的理解方式呢?

换个角度思考,引用也就是指针变量,那么?  明白了!因为引用本身根本就没有创建新的对象,因此不会删除对象的内存!

 

 

而且还发现

创建对象的顺序是p1、p2、p3

析构函数的顺序是p3、p2、p1

 

总结:

- 在针对对象中含有new的成员变量,需要特别注意!

- 如果有new的成员变量,注意函数是否会创建临时对象

- 创建的对象是深拷贝还是浅拷贝

 

按照上述三点考虑应该就能很好处理这次遇到的问题。

标签:函数参数,Age,运算符,Person,引用,重载,拷贝
From: https://www.cnblogs.com/henabo/p/16718797.html

相关文章

  • Go语言基础之运算符
    运算符Go语言内置的运算符有:算术运算符关系运算符逻辑运算符位运算符赋值运算符算术运算符运算符描述+相加-相减*相乘/相除%求余......
  • TypeScript 函数重载
    函数参数的类型可以使用联合类型?,让我们传递的值可以有多种类型的情况。下面是写的一个简单函数,参数x可以有number、string两种类型,返回值也是。functionreverse(x:......
  • 运算符
    运算符算术运算符算术运算符:+,-,*,/,%,++,-- ​​publicclassDemo5{publicstaticvoidmain(String[]args){//二元运算符  +,-,*,/,%inta=......
  • 运算符重载
    运算符重载一、加号重载运算符-实现两个自定义数据进行相加classPerson{public:Person(){};Person(inta,intb){this->m_A=a;......
  • java 动手动脑 方法重载
    如下代码://MethodOverload.java//UsingoverloadedmethodspackageHJssss;publicclasszhuce{ publicstaticvoidmain(String[]args){ System.out.printl......
  • 位运算符——三元运算符
      位:bit 三元表达式!条件表达式?表达式1:表达式2;若为真,执行表达式1若为假,执行表达式2例子:↓inta=10;intb=99;intres=a>b?a++:b--;运算结果:1......
  • 赋值运算符
        交换数,借助临时变量 intc=3;c+=4;//等价于c=c+4; ==> c=7; 特点:1.运算顺序从右到左2.赋值运算符的左边,只能是变量;;右边可以......
  • 逻辑运算符
      假设变量A=1,变量B=0,则存在途中实例。切记:真为1,假为0。    ......
  • 关系运算符
      非零为真(true),零为假(false)关系运算符的结果要么是1要么是0。 区分“=”赋值“==”等于a>b:称为关系表达式。例子:#include<stdio.h>voidmain(){inta......
  • Java基础08 自增自减运算符、初识Math类
    publicstaticvoidmain(String[]args){//++--自增自减一元运算符inta=3;intb=a++;//执行完这行代码后,先给b赋值,再自......