运算符重载

运算符重载分为两种形式,一种是成员函数重载,一种是全局函数重载。

  • +重载

  采用成员和全局重载的方法是相同的结果的,但是请注意全局重载有两个参数第一个参数是加号左边的值,第二个参数是加号右边的值;而对于成员函数重载只有一个参数,加号左边的对象是重载函数的调用者,加号右         边的对象作为参数传入重载函数。

  • <<重载

  需要认识到的是,ostream类中,cout对象是单例的,它没有拷贝函数,这就要求对<<重载函数的返回值类型必须是 ostream &。另外,由于cout是左值,调用的对象是右值,所以重载函数必须是全局重载,因为不能是

  object << cout。

  • ++重载

  这包含两种重载类型,一种是前置重载,一种是后置重载。前置递增没有参数,后置递增包含参数。

    1.前置重载

     在讨论前置递增之前,我们首先研究引用返回和值返回的区别。

     此处有一个类Dog,若有一个函数返回值是Dog,我们成为是值返回;如果返回值是Dog &,我们称这种返回叫做引用返回。值返回会产生一个临时变量,return的过程就是使用拷贝函数对临时对象赋值的过程,值得注意的是,临时对象的生命周期比函数内部的局部变量的生命周期更长;而引用返回则不同,return 的过程中不产生临时变量,这样不仅减少了内存资源的消耗,而且便于使返回值作为左值参与运算

     有了上面的分析,我们知道了,对于对此的递增运算,如++(++dog),其中 dog 是Dog类的一个对象,如果采用值返回,在进行了一次运算后,返回的是临时对象,这样dog本身不会在自增,基于此,我们可以得出自增运算符重载的函数返回值必须是引用类型。

    2.后置重载

     后置递增与前置递增不同,后置递增首先返回该对象的值,再将对象自增。

     后置递增的声明:Dog operator++(int),注意后置自增的展位参数必须是 int 类型

     后置递增返回类型必须是值返回,因为下面的代码中,tmp 是局部变量,再执行完自增后,函数中定义的局部变量就会被销毁,这个时候对该对象的访问时非法的

  • =重载

  重载首先应该进行深拷贝。  

  赋值运算符重载需要注意的是,对于连续赋值的情况,如 d1 = d2 =d3;  。这种情况下,重载的方式非常丰富具体可以参见另一位大佬的博客,下面给出链接:

  https://www.cnblogs.com/zpcdbky/p/5027481.html

  

#include <iostream>
#include <string>


using namespace std;

class Dog {
private: 
    string name;
    int age;
public:
    Dog(string name, int age) {
        cout << "调用参数构造函数。" << endl;
        this->name = name;
        this->age = age;
    }
    Dog(const Dog& d) {
        cout << "调用复制构造函数。" << endl;
        name = d.name;
        age = d.age;
    }
    ~Dog() {
        cout << "调用析构函数。" << endl;
    }
    
    Dog operator+(Dog& d);

    Dog& operator++();
    
    Dog operator++(int);

    Dog operator=(const Dog& d);

    string getName() const {
        return name;
    }

    int  getAge() const {
        return age;
    }

    Dog setAge(int age) {
        this->age = age;
        return *this;
    }

    void show() {
        cout << name << '\t' << age << endl;
    }
};

//加号成员函数重载
Dog Dog::operator+(Dog& d) {
    this->age += d.age;
    return*this;
}

//加号全局函数重载
Dog operator+(const Dog& d, int x) {
    cout << "--------" << endl;
    Dog tmp(d.getName(), d.getAge());
    cout << "--------" << endl;
    return tmp.setAge(tmp.getAge() + x);
}

//左移运算符重载
ostream& operator<<(ostream& cout, const Dog& d) {
    cout << d.getName() << '\t' << d.getAge();
    return cout;
}

//前置递增,返回类型必须是引用返回
Dog& Dog::operator++() {
    age++;
    return *this;
}

//后置递增,返回类型必须是值返回
Dog Dog::operator++(int) {
    cout << "--------" << endl;
    Dog tmp = *this;
    cout << "--------" << endl;
    age++;
    cout << "C++17新特性,将返回值优化,对于局部变量的值返回,不再进行复制构造。tmp不再被复制。" << endl;
    return tmp;
}

//赋值运算符重载,赋值运算的返回值必须是引用,这样对于连等操作才会合法
Dog Dog::operator=(const Dog& d) {
    cout << "开始赋值。" << endl;
    this->name = d.getName();
    this->age = d.getAge();
    
    cout << "值返回。" << endl;
    return *this;
}


int main() {

    Dog d1("eta", 0);
    Dog d2("vii", 1);

    d1 = d1 + d2;

    cout  << "d1 = " << d1 << endl;
    cout  << "d2 = " << d2 << endl;

    d2 = d2 + 10;
    cout << d2 << endl;

    cout << "d1两次前置递增:  " << ++(++d1) << endl;

    cout << "d2单次后置递增进行时:" << d2++ << endl;
    cout << "d2后置递增完成后: " << d2 << endl;
    
    d1 = d2;
    cout << "将d1赋值给d2: " << d1 << endl;

    Dog d3("none", -1);

    cout << "\n连等:" << endl;
    d1 = d2 = d3;
    cout << "连续赋值后:" << endl;
    cout << "d1: " << d1 << endl;
    cout << "d2: " << d2 << endl;
    cout << "d3: " << d3 << endl;
    cout << "结束。" << endl;
    return 0;
}

 

posted @ 2023-02-24 23:56  Meetalone  阅读(46)  评论(0编辑  收藏  举报