zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++学习笔记_08 运算符重载 2021-04-22

C++笔记学习 2021 运算符 04 22 08
2023-09-27 14:25:47 时间
//C++学习笔记_08 运算符重载

#include<cstdio>
#include<iostream>
using namespace std;
//有理数类
class CRationalNum
{
private:
    int bad;  //分母为0,这是一个无效的数 bad=1 表示数字无效 
    int num;  //分子
    int den;  //分母
public:
    CRationalNum() :num(0), den(1),bad(0){} //默认值是 0
    CRationalNum(int x, int y=1) :num(x), den(y), bad(0) //int y=1:C++里面可以定义参数的默认值
    { reduct();} 

    //约分的函数(找最大公约数--辗转相除法)
    void reduct(){
        if (den == 0)//分母为0,这个数无效
        { bad = 1;return; }
        if (num == 0)//值必然为0
        { den = 1; return;}
        if (den < 0) //分母为负数,把符号给分子
        { num = -num;den = -den; }

        int d_num = num;// d_num 取分子的绝对值
        if (num < 0){ d_num = -num;}

        int x = d_num > den ? d_num : den; //x 取两个里面大的
        int y = d_num > den ? den : d_num; //y 取两个里面小的
                                           //= d_num + den - x
        int c = x % y;
        while (c)
        { x = y;y = c;c = x % y; }
        //c == 0 时,得到最大公约数 y
        num /= y;den /= y;return;
    }
    //输入的时候, rNum 会被修改,不能再使用 const
    friend istream& operator >> (istream &is, CRationalNum &rNum)
    {
        is >> rNum.num >> rNum.den;
        rNum.reduct();
        return is;
    }

    //重载输出运算符 << 
    //1:友元
    //2:返回值 是 ostream
    //3:入参加上 ostream
    //4:入参是 ostream 引用
    //5:返回值是引用类型
    friend ostream& operator << (ostream &os, const CRationalNum &rNum)
    {
        //这里面就没有了 num, 和 den,也没有 this 指针
        //没有this指针,也就是说,这个函数不是 CRationalNum 的成员函数
        //而是一个外部函数(或者说是 cout 对象的成员函数)
        //外部函数,要访问自己的私有成员 ---》需要函数声明成 friend
        //cout 是 ostream 的对象,这里要体现的话,只能是入参
        //返回值:cout << a << b  ==> 可以看作 xxx = cout << a; xxx << b;
        //      这里连续输出,应该返回 ostream 对象

        if (rNum.bad == 1) { os << "NaN";}
        else if (rNum.den == 1) { cout << rNum.num;}
        else { cout << rNum.num << "/" << rNum.den;}
        return os; //返回一个局部变量,不允许
                   // --> 把入参声明从引用
                   //ostream 的对象,不允许复制,
                   //     作为返回值,有可能赋值给别人,不允许
                   //     --》返回值类型,定义成引用
    }

    //重载 + 运算符 //operator 声明 + 是一个运算符函数
    //运算符重载 xxx,就是在本来应该写函数名的地方,写上 operator xxx 
    CRationalNum operator + (const CRationalNum &rNum) const
    {
        //括号里面的const 表示 rNum 是常量,不允许函数内部修改 rNum 的值
        //外面的const 修饰的是函数,表示函数内不能够修改 成员变量        
        if (this->bad == 1) { return *this;}//bad 表示这个数非法
        else if (rNum.bad == 1) { return rNum;}
        else{
            //   a/b + c/d = (a*d+c*b)/b*d 
            int x; //保存结果分子部分
            int y; //保存结果分母部分
            x = num * rNum.den + rNum.num * den;
            y = den * rNum.den;
            return CRationalNum(x, y);
        }
    }

    void Print(){
        if (bad == 1) { cout << "NaN" << endl; }
        else if (den == 1) { cout << num << endl; }
        else { cout << num << "/" << den << endl; }
        return;
    }

    //1: 分数的运算: 加减乘除
    //2: 分数的输入输出:
    //3: 约分
    CRationalNum add(const CRationalNum &rNum) const
    {
        if (this->bad == 1) { return *this;}//bad 表示这个数非法
        else if (rNum.bad == 1){ return rNum;}
        else{
            //   a/b + c/d = (a*d+c*b)/b*d 
            int x; //保存结果分子部分
            int y; //保存结果分母部分
            x = num * rNum.den + rNum.num * den;
            y = den * rNum.den;
            return CRationalNum(x, y);
        }
    }

    /*
    //4:  分母为 0 怎么处理? --》就是一个无穷大(无穷小[分子为负数])的数
    //    4-0: 分子为 0,则无论分母是多少,都认为这个数都是 0
    //    4-1: 无穷大(小)数+正常的数 = 无穷大(小)数
    //    4-2: 无穷大(小)数 + 无穷大(小)数 = 无穷大(小)数
    //    4-3: 无穷大数+无穷小数  = 0
    
    //方案1:定义函数做加减乘除运算
    CRationalNum add(const CRationalNum &rNum) const
    {
        //两个有理数相加:
        //  但是,我们这里只看到了 1 个有理数 rNum,还一个在哪里?
        //  还有一个对象,就是调用 add 成员函数的这个对象,*this
        //  rNum1.add(rNum2)
        //注意: 
        //   1: den 是 rNum 的私有成员,这里 可以通过 rNum.den 来访问
        //      因为:只要是在类的成员函数里面,就允许直接使用
        //   2: 谁调用了 add 函数,那么函数里面的 this 变量,就指向谁
        //      this 指向 CRationNum 对象的指针
        //      比如 rNum1.add(rNum2)
        //           --> this 就是 &rNum1; *this 就是 rNum1
        //一般情况下 this->num, this->den 可以直接写为 num, den
        //在入参和 这个变量重名的情况下,我们再使用 this 来进行区分
        if (den == 0 && rNum.den == 0) //就是 *this.den (this->den)
        {
           //两个无穷数
           if (num * rNum.num > 0){ return rNum;} //同为无穷大或者同为无穷小
           else   //一个无穷大一个无穷小
           {return CRationalNum();}//类名后加一个括号,表示生成一个匿名对象
        }
        else if (den == 0) { return *this;}
        else if (rNum.den == 0) { return rNum; }
        else{
            //   a/b + c/d = (a*d+c*b)/b*d 
            int x; //保存结果分子部分
            int y; //保存结果分母部分
            x = num * rNum.den + rNum.num * den;
            y = den * rNum.den;
            return CRationalNum(x, y);
        }
    }
    */
};

int main()
{
    CRationalNum rNum1;
    CRationalNum rNum2(42,111);
    CRationalNum rNum3(42, 0);

    rNum1.Print();
    rNum2.Print();
    rNum3.Print();

    CRationalNum rNum4(-1, 2);
    CRationalNum rNum5(1, 6);

    rNum1 = rNum4.add(rNum5);
    rNum1.Print();

    //1: 对有理数做加减乘除运算,能不能 直接使用 rNum1 = rNum4 + rNum5 ?
    //2: 输出的时候,能不能直接使用 cout << rNum1 << endl;
    //--> 运算符重载 :使用  operator + 替代 函数名 add

    rNum1 = rNum4 + rNum5; //这里 rNum4 调用了 + 号运算
                           //入参是 rNum5
    rNum1.Print();

    rNum1 = CRationalNum(1,2) + CRationalNum(1,3) + CRationalNum(1, 4);
    cout << "\nrNum1:";
    rNum1.Print();

    //关于输出:前面有东西还得分开写,
    //          Print() 自带换行,如果我们想一行输出两个分数,没办法
    //我们能不能 简单点 使用 cout << rNum 进行输出?
    //--> 重载输出运算符
    //cout << rNum1; // cout 这个对象, 调用了 << 运算符,入参是 rNum1
    //这里,不再是 rNum1 调用某个函数
    //所以,这个运算符重载 rNum1 是入参
    
    rNum1 = rNum4 + rNum5;
    cout << rNum4 << " + " << rNum5 << " = " << rNum1 << endl;
    //注意:上述语句,调用了 3 次 << 运算符重载

    cout << "输入有理数:";
    cin >> rNum1;
    cout << "rNum:" << rNum1 << endl;

	return 0;
}

//作业:
//1: 实现 -, *, / 运算符重载
//2: 实现 >> 输入运算符重载
//3: 比较运算重载 >,  >=, <, <=, ==, !=
//4: ++, --, +N , -N, +=,-=  重载
//    ++,-- 涉及到前加加,后加加
#include <iostream>
using namespace std;
class Point
{
private:
	int a,b;
public://成员函数 
	Point():a(0),b(0){}
	Point(int a,int b){
		this->a=a;this->b=b;
	}
	void Print(){
		cout<<a<<" "<<b<<endl;return;
	}
	Point add(const Point &rNum)const{
		int x=rNum.a+a;
		int y=rNum.b+b;
		return Point(x,y);
	}
public://重载函数 

	friend ostream& operator << (ostream &os, const Point &rNum){
		cout<<rNum.a<<" "<<rNum.b;return os;
	}
	friend Point operator * (const Point &,const Point &);
	friend Point operator / (const Point &,const Point &);
	Point operator +(const Point &rNum) const{
		int x=rNum.a+a;
		int y=rNum.b+b;
		return Point(x,y);
	}
	Point operator -(const Point &rNum) const{
		int x=a-rNum.a;
		int y=b-rNum.b;
		return Point(x,y);
	}
};
Point operator * (const Point &rNum1,const Point &rNum2){
	Point ret;
	ret.a=rNum1.a*rNum2.a;
	ret.b=rNum1.b*rNum2.b;
	return ret;
}
Point operator / (const Point &rNum1,const Point &rNum2){
	Point ret;
	ret.a=rNum1.a/rNum2.a;
	ret.b=rNum1.b/rNum2.b;
	return ret;
}
int main()
{
	Point rNum1; 
	Point rNum2(5,10); 
	Point rNum3(3,19); 
	
	rNum1.Print();
	rNum2.Print();
	rNum3.Print();
	
	rNum1=rNum2+rNum3;
	rNum1.Print();
	cout<<rNum1<<" = "<<rNum2<<" + "<<rNum3<<endl;
	
	rNum2=rNum1-rNum3;
	rNum2.Print();
	cout<<rNum2<<" = "<<rNum1<<" - "<<rNum3<<endl;
	
	rNum1=rNum2*rNum3;
	rNum1.Print();
	cout<<rNum1<<" = "<<rNum2<<" - "<<rNum3<<endl;
	
	rNum2=rNum1/rNum3;
	rNum2.Print();
	cout<<rNum2<<" = "<<rNum1<<" / "<<rNum3<<endl;
	
	return 0;
}