首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ 運算符重載實戰:分數類輸入輸出流重載常見錯誤與修正

     編輯:程式設計綜合問答

問題背景

在 C++ 作業中,為 fraction(分數)類重載 operator<< 和 operator>> 是經典練習。許多初學者在實現輸入輸出運算符重載時,容易在語法細節、參數傳遞、流狀態處理上踩坑。本文針對典型錯誤代碼,逐行分析並給出修正方案。

錯誤代碼回顧

// 類聲明片段
friend ostream& operator<<(ostream& cout, const fraction& a);
friend istream& operator>>(istream& cin, fraction& a);

// 實現文件
ostream& operator<<(ostream& cout, const fraction& a)
{
    cout < return cout;  // 錯誤 1:語法錯誤,缺少運算對象
}

istream& operator>>(istream& cin, fraction& a)
{
    cin >> a.rn >> "/" a.dn >> endl;  // 錯誤 2:字符串字面量不能直接作為提取目標
    return cin;
}

核心錯誤分析

1. 輸出運算符 operator<<

  • 語法錯誤:cout < return cout; 中 < 後缺少右操作數。應輸出分數的具體格式,如 a.numerator << "/" << a.denominator。
  • 參數命名:慣例用 os 或 out 而非 cout,因該流未必是標準輸出。
  • const 正確性:第二參數應為 const fraction&,已正確。

2. 輸入運算符 operator>>

  • 分隔符處理錯誤:cin >> a.rn >> "/" a.dn 試圖將字符串 "/" 作為提取目標,編譯不通過。正確做法是讀取一個 char 變量暫存分隔符:char slash; cin >> a.rn >> slash >> a.dn; 並檢查 slash == '/'。
  • 流狀態檢查缺失:輸入失敗時(如非數字、格式錯誤)應保持流錯誤狀態,不修改對象。
  • 參數命名:慣例用 is 或 in。

修正後的標準實現

#include <iostream>
using namespace std;

class fraction {
    int num;   // 分子
    int den;   // 分母
public:
    fraction(int n = 0, int d = 1) : num(n), den(d) { normalize(); }

    // 友元聲明
    friend ostream& operator<<(ostream& os, const fraction& f);
    friend istream& operator>>(istream& is, fraction& f);

private:
    void normalize() {
        if (den < 0) { num = -num; den = -den; }
        int g = gcd(abs(num), den);
        num /= g; den /= g;
    }
    static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
};

// 輸出:格式 "num/den"
ostream& operator<<(ostream& os, const fraction& f) {
    os << f.num << '/' << f.den;
    return os;
}

// 輸入:期望格式 "num/den",允許前後空白
istream& operator>>(istream& is, fraction& f) {
    int n, d;
    char slash;
    // 嘗試讀取 分子 '/' 分母
    if (is >> n >> slash >> d) {
        if (slash == '/' && d != 0) {
            f = fraction(n, d);  // 利用構造函數歸一化
        } else {
            is.setstate(ios::failbit);  // 格式錯誤或分母為 0
        }
    }
    // 讀取失敗時,f 保持原值,流狀態已為 failbit
    return is;
}

// 測試主函數
int main() {
    fraction f1(3, 4), f2;
    cout << "f1 = " << f1 << endl;  // 輸出: f1 = 3/4

    cout << "請輸入分數 (格式: 5/6): ";
    if (cin >> f2) {
        cout << "f2 = " << f2 << endl;
    } else {
        cerr << "輸入格式錯誤!" << endl;
    }
    return 0;
}

進階避坑指南

  1. 不要在重載函數內使用 cout/cin,必須使用傳入的流參數 os/is,才能支持文件流、字符串流等。
  2. 輸入運算符應具備異常安全性:讀取失敗時不修改目標對象(上例利用臨時變量 n, d 實現)。
  3. 考慮輸出格式控制:可配合 iomanip 或自定義格式標志,但教學階段保持簡單即可。
  4. 友元 vs 成員:雙目運算符(如 +、<<)常用友元或非成員函數,保持左操作數為流對象。

總結

運算符重載的核心在於保持語義直觀、參數正確、流狀態維護。輸入輸出重載更是考驗對流機制理解的試金石。掌握上述模板,配合 normalize() 等輔助邏輯,即可輕松應對分數類及類似作業。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved