C++类和对象--之五--运算符重载

还是用代码做笔记吧

#ifndef _CLASSDEMO_H_
#define _CLASSDEMO_H_


namespace PoEdu
{
    class ClassDemo
    {
    public:
        ClassDemo();
        ClassDemo(int num);
        ClassDemo &operator=(const ClassDemo &other);
        ClassDemo(const ClassDemo &other);  // 拷贝构造函数,它的格式是固定的,它的格式无法发生改变,所以它是无法重载的
                                            // 那么我们不写,编译器会默认帮我们生成一个,如果写了,编译器就不再生成了

        //// 如果我们写了这样一个函数,那么就永远无法通过编译的,会涉及到一个东西是 无限递归
        //// 那么为什么会进行无限递归呢?原因很简单,因为形参在被调用的时候,要被实参化,实参化就是进行一个拷贝,那么在拷贝的时候
        //// 就会调用一个构造函数(即拷贝构造函数,那么拷贝构造函数就是它本身),所以就变成了无限的递归
        //ClassDemo(const ClassDemo other)
        //{
        //  
        //}

        ~ClassDemo();

        int GetNum() const;

    private:
        int _num;
    };
}

#endif // !_CLASSDEMO_H_
#include "ClassDemo.h"
#include <iostream>


namespace PoEdu
{
    ClassDemo::ClassDemo()
    {
        std::cout << "ClassDemo(" << _num << ")" << std::endl;
    }
    // 初始化列表
    ClassDemo::ClassDemo(int num) : _num(num)
    {
        std::cout << "ClassDemo(" << num << ")" << std::endl;
    }

    ClassDemo& ClassDemo::operator=(const ClassDemo& other)
    {
        std::cout << "operator=(const ClassDemo& other)" << _num << std::endl;
        _num = other._num;

        return *this;
    }

    ClassDemo::ClassDemo(const ClassDemo& other)
    {
        std::cout << "ClassDemo(const ClassDemo& other)" << _num << std::endl;
        _num = other._num;
    }

    ClassDemo::~ClassDemo()
    {
        std::cout << "~ClassDemo(" << _num << ")" << std::endl;
    }

    int ClassDemo::GetNum() const
    {
        return _num;
    }
}
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "ClassDemo.h"


// 模拟所有的int操作
class Integer
{
public:
    // 1. operator函数可以重载
    // 2. 符号 运算符    =  >  <  ==  != +  -  &  |  !  new()  sizeof()
    // 无法重载的运算符(总共有5个)  ::(作用域运算符)  ? :(三目运算符)  .(直接成员访问运算符)  ->(间接成员访问运算符)  *.(应该叫类成员指针运算符)
    // 其实上面五个运算符也没有重载的必要性
    // &(取地址运算符),它也是默认生成的一个函数,它return的是this,这个我们一般也不用去管
    // 


    Integer(int num = 0) :_num(num)
    {
        std::cout << "Integer(int num = " << _num << ")" << std::endl;
    }
    // 拷贝构造函数
    Integer(const Integer &other) : _num(other._num)
    {
        std::cout << "Integer(const Integer &other = " << _num << ")" << std::endl;
    }


    // 默认的operator=函数返回的是当前对象的引用
    // 那么我们写成 void 类型有问题吗?我们获取一下 _num 看看,我们赋值一次没有问题
    // 但是如果我们想多次进行赋值,那么返回void就会出问题了
    /*void operator=(const int num)
    {
        _num = num;
        std::cout << "operator=(" << num << ")" << std::endl;
    }*/
    Integer &operator=(const int num)
    {
        _num = num;
        std::cout << "operator=( int " << num << ")" << std::endl;
        return *this;
    }
    // 默认的赋值函数
    Integer &operator=(const Integer &other)
    {
        std::cout << "operator=( const Integer & )" << _num << std::endl;
        _num = other._num;
        return *this;
    }
    // 这个和上面的void一样,也是不能连续赋值
    //void operator+(int num)
    //{
    //  _num += num;
    //}

    Integer operator+(int num)
    {
        Integer temp;
        temp = _num + num;

        return temp;
    }

    // friend修饰后的函数,这个函数就不属于我们的类了,所以也就没有this指针了,
    // 即使我们写到类的里面,也不是类的成员函数
    friend Integer operator+(int num, const Integer &other)
    {
        Integer temp;
        temp._num = num + other._num;
        return temp;
    }

    // ++是一个一元操作符
    // 前++调用不带参数的operator++
    Integer &operator++()
    {
        ++_num;
        return *this;
    }
    // 后++调用带参数的operator++
    Integer operator++(int)
    {
        Integer temp = *this;
        ++_num;

        return temp;
    }

    // 关系运算符
    bool operator==(const Integer &other)
    {
        return _num == other._num;
    }

    // << >>
    // 流运算符,输出输入
    friend std::ostream &operator<<(std::ostream &os, const Integer &other)
    {
        os << other._num;
        return os;
    }

    friend std::istream &operator>>(std::istream &os, Integer &other)
    {
        os >> other._num;

        return os;
    }


    int GetNum()
    {
        return _num;
    }


    ~Integer()
    {
        std::cout << "~Integer(" << _num << ")" << std::endl;
    }

private:
    int _num;
};

Integer f1()
{
    return Integer(10);
}

Integer &f2()
{
    return Integer(20);
}



int main()
{
    using namespace PoEdu;

    // demo1
    // 当前面没有参数进行接收的时候,会打印出这样的结果
    // Integer(int num = 10)
    //  ~Integer(10)
    //  Integer(int num = 20)
    //  ~Integer(20)
    //f1();
    //f2();

    // demo2
    // 那么,当前面有对象进行接收的时候,又会是怎么样呢?
    // Integer(int num = 10)
    //  Integer(int num = 20)
    //  ~Integer(20)
    //  Integer(const Integer &other = 16039936)
    //Integer i1 = f1();    // 构造函数
    //Integer i2 = f2();    // 构造函数
    // demo3
    Integer i1; // 默认构造函数
    Integer i2; // 默认构造函数
    i1 = f1();
    i2 = f2();
    // 上面的代码会调用下面的
    // Integer(int num = 0)
    //  Integer(int num = 0)
    //  Integer(int num = 10)
    //  operator=(const Integer &)0
    //  ~Integer(10)
    //  Integer(int num = 20)
    //  ~Integer(20)
    //  operator=(const Integer &)0

    // 从上面的三个例子可以看出,返回一个临时对象和返回一个临时对象的引用是不一样的,区别在于
    // 1. 返回对象,会在函数结束后,并将值赋值给其它对象后,才会析构
    // 2. 而返回引用,则在当前方法调用完之后,直接析构
    // 这就是两者最大的区别



    Integer demo = 10, other = 20;
    //other = demo = 100;
    // 如果我们不写赋值函数,那么我们就需要下面三个步骤才能完成上面的操作
    // 1. 构造 temp 对象 Integer(100)
    // 2. 调用 operator=(const Integer &other) 赋值函数
    // 3. 析构 temp 对象
    // 所以为了提高效率,我们可以对operator=的方法进行重载

    //Integer *p = &demo;
    // 此时没有问题,说明生成了 &运算符
    //Integer other = *p;
    // 说明生成了解指针运算符
    // 所以一个空类当中,默认的给我们生成了以下六个函数
    // 构造
    // 析构
    // 赋值
    // 拷贝构造函数
    // operator&
    // operator*

    other = demo = 100;
    // 我们将这一句话进行分解,分解过程如下所示,如果返回值是void,
    // 那么other.operator=(demo.operator=(100))这句话就有问题了,所以,返回值必须是对象的引用
    //demo = 100;
    //demo.operator=(100);
    //other = demo;
    //other.operator=(demo);
    //other.operator=(demo.operator=(100));

    other = demo + 1;
    other = 10 + demo;

    std::cout << demo.GetNum() << std::endl;
    std::cout << other.GetNum() << std::endl;

    demo = 100 + other + 1000;
    // 它会是怎么样的一个调用顺序呢?
    // friend  operator+  赋值
    // 为什么会是这样的顺序呢?暂时还不清楚,先记住吧

    demo++;
    ++demo;

    std::cout << demo << std::endl;


    return 0;
}

欢迎大家批评指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值