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

简介: C++学习笔记_08 运算符重载 2021-04-22
//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;
}
相关文章
|
4月前
|
C++
c++学习笔记07 结构体
C++结构体的详细学习笔记07,涵盖了结构体的定义、使用、数组、指针、嵌套、与函数的交互以及在结构体中使用const的示例和解释。
40 0
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5
|
3月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
3月前
|
安全 C语言 C++
C++学习笔记
C++学习笔记
|
4月前
|
C++
【学习笔记】【C/C++】 c++字面值常量
【学习笔记】【C/C++】 c++字面值常量
46 1
|
4月前
|
存储 C++
c++学习笔记05 函数
C++函数使用的详细学习笔记05,包括函数的基本格式、值传递、函数声明、以及如何在不同文件中组织函数代码的示例和技巧。
38 0
c++学习笔记05 函数
|
4月前
|
编译器 C++
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
58 0
|
4月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
51 0
|
4月前
|
C++
c++学习笔记09 引用
C++引用的详细学习笔记,解释了引用的概念、语法、使用注意事项以及引用与变量的关系。
44 0
|
4月前
|
存储 程序员 编译器
c++学习笔记08 内存分区、new和delete的用法
C++内存管理的学习笔记08,介绍了内存分区的概念,包括代码区、全局区、堆区和栈区,以及如何在堆区使用`new`和`delete`进行内存分配和释放。
52 0