重載<<操作符


回頭看我們之前的 rational.cpp,你滿意了嗎?反正我是覺得那些代碼的可讀性仍然欠佳:main 函數里邊要多次調用 print 方法才能實現分數打印,醬紫不行!

如何通過重載 << 操作符來實現 print 打印分數的功能。( <<官方叫插入器 )

你或許知道,或許不知道,從第一次輸出值開始,<< 操作符就一直被重載!

例如:std::cout << “Hello FishC!”;

C 標准庫對左移操作符(<<)進行了重載,讓它可以把值發送到一個流去(流的概念)。 但是在這個栗子中,iostream 庫對新的 Rational 類表示一無所知,所以不能直接用 << 來輸出我們的有理數(分數)。 但是,沒有什么能夠阻擋我們重載 << 操作符來讓它接受 Rational 對象的宏偉願望!

另外一個原因也比較重要:因為,重載的含義本身就是可以用相同的名字去實現不同的功能:輸入參數方面有所差異就不會有問題。當然,我們無法在現有的 ostream 類里專門添加一個新的 operator <<()方法。所以我們只能定義一個正常的函數在外部重載這個操作符,這與重載方法的語法大同小異,唯一的區別是不再有一個對象可以用來調用 << 重載函數,而不得不通過第一個輸入參數向這個重載方法傳遞對象。注意區別前邊我們對四則運算符的重載。

下面是一個 operator <<()函數的原型:

std::ostream& operator<<( std::ostream& os, Rational f );
  • 第一個輸入參數 os 是將要向它寫數據的那個流,它是以“引用傳遞”方式傳遞的。
  • 第二個輸入參數是打算寫到那個流里的數據值,不同的 operator <<()重載函數就是因為這個輸入參數才相互區別的  
  • 返回類型是 ostream 流的引用。一般來說,在調用 operator <<()重載函數時傳遞給它的是哪一個流,它返回的就應該是那個流的一個引用。

好了,介紹就說這么多,我們對 Rational.cpp 進行改造吧:Rational2.cpp

#include <iostream>
#include <string>
#include <stdlib.h>

class Rational
{
public:
    Rational(int num, int denom);  // num = 分子, denom = 分母

    Rational operator+(Rational rhs); // rhs == right hand side
    Rational operator-(Rational rhs);
    Rational operator*(Rational rhs);
    Rational operator/(Rational rhs);

private:
    void normalize(); // 負責對分數的簡化處理

    int numerator;    // 分子
    int denominator;  // 分母

    friend std::ostream& operator<<(std::ostream& os, Rational f);
};

Rational::Rational(int num, int denom)
{
    numerator = num;
    denominator = denom;

    normalize();
}

// normalize() 對分數進行簡化操作包括:
// 1. 只允許分子為負數,如果分母為負數則把負數挪到分子部分,如 1/-2 == -1/2
// 2. 利用歐幾里德算法(輾轉求余原理)將分數進行簡化:2/10 => 1/5
void Rational::normalize()
{
    // 確保分母為正
    if( denominator < 0 )
    {
        numerator = -numerator;
        denominator = -denominator;
    }

    // 歐幾里德算法
    int a = abs(numerator);
    int b = abs(denominator);

    // 求出最大公約數
    while( b > 0 )
    {
        int t = a % b;
        a = b;
        b = t;
    }

    // 分子、分母分別除以最大公約數得到最簡化分數
    numerator /= a;
    denominator /= a;
}

// a   c   a*d   c*b   a*d + c*b
// - + - = --- + --- = ---------
// b   d   b*d   b*d =    b*d
Rational Rational::operator+(Rational rhs)
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;

    int e = a*b + c*d;
    int f = b*d;

    return Rational(e, f);
}

// a   c   a   -c
// - - - = - + --
// b   d   b   d
Rational Rational::operator-(Rational rhs)
{
    rhs.numerator = -rhs.numerator;

    return operator+(rhs);
}

// a   c   a*c
// - * - = ---
// b   d   b*d
Rational Rational::operator*(Rational rhs)
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;

    int e = a*c;
    int f = b*d;

    return Rational(e, f);
}

// a   c   a   d
// - / - = - * -
// b   d   b   c
Rational Rational::operator/(Rational rhs)
{
    int t = rhs.numerator;
    rhs.numerator = rhs.denominator;
    rhs.denominator = t;

    return operator*(rhs);
}

std::ostream& operator<<(std::ostream& os, Rational f);//函數聲明 

int main()
{
    Rational f1(2, 16);
    Rational f2(7, 8);

    // 測試有理數加法運算
    std::cout << f1 << " + " << f2 << " == " << (f1+f2) << "\n";

    // 測試有理數減法運算
    std::cout << f1 << " - " << f2 << " == " << (f1-f2) << "\n";

    // 測試有理數乘法運算
    std::cout << f1 << " * " << f2 << " == " << (f1*f2) << "\n";

    // 測試有理數除法運算
    std::cout << f1 << " / " << f2 << " == " << (f1/f2) << "\n";

    return 0;
}

std::ostream& operator<<(std::ostream& os, Rational f)
{
    os << f.numerator << "/" << f.denominator;
    return os;
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM