1
std::istream & operator >>(std::istream & ins, Rational & target)
{
    int num, den;
    char symb;          
    std::cout << "Please enter a rational number: ";
    ins >> num >> symb >> den;
    std::cout << std::endl;

    if(validateInput(num, symb, den)){
        target = Rational(num, den);            
        return ins;
    }
    else{
        std::cin >> target;
    }
}

bool validateInput(int num, char symb, int den)
{
    if(symb != '/'){
        std::cout << "Error: Illegal format. Please use '2/4'." << std::endl;
        return false;
    }
    if((static_cast<int>(num) != num) && (static_cast<int>(den) != den)){
        std::cout << "Error: Not a valid rational number." << std::endl;
        return false;
    }
    if(den == 0){
        std::cout << "Error: Cannot divide by 0." << std::endl;
        return false;
    }

    return true;
}

「x/y」の形式で有理数を取り込んでいるので、たとえば 2/4 です。正しく入力するとうまくいきます。2p4 と入力すると、正しいエラー (「/」が欠落している) が表示され、新しい番号を要求されます。分母に 0 が含まれている場合は、エラーが報告され、新しい数値が要求されます。

しかし、それが有効な番号かどうかを確認することはうまくいかないようです。「a/4」と入力すると、クラッシュするまで無限にループします。理由がわかりません。デバッガーを確認すると、ins >> ステートメントに戻りますが、ユーザーに何も要求しません。

私の論理がどこか間違っていると思います。注意してください、私はC ++にかなり慣れていないので、まだ学んでいます。以前に例外処理を試みていましたが、まだ適切に学習していなかったので、より慣れ親しんだものに落ち着きました。

ありがとう!

4

2 に答える 2

5

この問題の基本的な要点は、ストリームの状態が悪くなると、C++ ストリームでフォーマットされた抽出演算子が機能しなくなり、再度機能させるには状態をリセットする必要があることです。

他にも問題があります。

まず第一に、検証関数はあなたの経験不足を明らかにします:static_cast<int>(intval) == intval常に真であり、何も確認しません。次に、ストリームからの値の抽出に実際に成功したことを検証できません (これが無限ループの原因です。検証に何度も失敗するだけです)。

したがって、値を抽出するときは、次のようにすべてがうまくいったことを確認する必要があります。

int num, den;
char symb;
// Remember to flush unfinished lines
std::cout << "Please enter a rational number: " << std::flush; 
if (std::cin >> num >> symb >> den)
    // you extracted an integer, a character and an integer succesfully
    // perhaps check that the character is '/' and denominator is non-zero
else
    // there was an error: what should we do?

「何をすべきか」の部分は明らかではありません。合理的 (かつ直感的) であると思われる場合は、ストリームをリセットして最初の問題のあるバイトを削除し、再試行することができますただし、数が大きすぎるために抽出が失敗した可能性もあります。その場合、これは奇妙な動作につながる可能性があります: 次の入力を考慮してください (一般的なlongサイズの実装で):

3111111111111111111111111111111111111111111111111/3

実際の仕様がない場合、考慮すべきことは行指向の入力です。最初に行を読み取り、それを解析してみてください。うまくいかない場合は、無視して次を試してください。

于 2012-09-01T02:53:22.120 に答える
0

入力ストリームの重要な概念の 1 つは、入力ストリームが特定のデバイスに関連付けられていないことです。つまり、コンソールの場合、ファイルの場合、文字列の場合など、何でもstr >> rational機能するはずです。strしたがって、エクストラクタは抽出する必要があります。プロンプトを表示するべきではなく、何が気に入らなかったのかを説明するべきではありません。これらはすべて、エクストラクタを呼び出すコードで実行する必要があります。

エクストラクタでの検証は問題ありませんが、エラーが検出された場合、それを報告する通常の方法は例外をスローすることです。エラーコードやテキスト文字列を保持したり、エラーごとに異なる例外を設定したり、好きなように例外を実行させることができます。エクストラクタを呼び出して例外をキャッチし、適切な応答を決定するのは、コードの責任です。

static_cast<int>(num) != num

numは int なので何static_castもしません。このテストは決して失敗しません。

int main() { try { std::cout << "有理数を入力してください: "; 有理r; std::cin >> r; } catch(...) { std::cout << "問題が発生しました\n"; } }

テスト目的で、このバージョンのmain()を書き直して、文字列ストリームを入力ソースとして使用し、"2/4"または"2^4"テストしたいもので初期化します。これにより、毎回入力する必要がなくなります。

于 2012-09-01T11:43:08.503 に答える