1

C++ でオーバーロードされた演算子について学んでいますが、問題があります。

C++ で分数を表す (プリミティブ) クラスと、そのうちの 2 つを乗算する関数を作成しました。

関数を使用して分数を整数で乗算したい場合、すべてがうまく機能します (変換コンストラクター:P のおかげです)。しかし今、2 つの数値のように、オーバーロードされた * で分数を乗算したいと考えています。乗算first_fraction * second_fractionはうまく機能しますが、コンパイラは数値を分数に変換したくありませんfraction * 2。(このエラーが発生しました: error C2666: 'operator *' : 2 つのオーバーロードには同様の変換があります)

手動で変換すると、fraction*static_cast<CFraction>(2)再び機能します。

誰が私が悪いことをしているのか説明できますか? 完全なコードは次のとおりです。

#include <iostream>

using namespace std;

class CFraction
{

private:
    int m_numerator;
    int m_denominator;

public:

    // Normal constructor, default constructor and conversion constructor
    CFraction(int numerator=0,int denominator = 1) : m_numerator(numerator), m_denominator(denominator)
    {               
    }

    int numerator() const { return m_numerator; }
    void numerator(int numerator) { m_numerator = numerator; }

    int denominator() const { return m_denominator; }
    void denominator(int denominator) { m_denominator = denominator; }

    // Conversion to decimal form
    operator float()
    {
        return m_numerator / static_cast<float>(m_denominator);
    }   

};

// Function to multiply 2 fractions
CFraction multiplication(const CFraction& f1,const CFraction& f2)
{
    return CFraction(f1.numerator()*f2.numerator(),f1.denominator()*f2.denominator());
}

// Overloaded opearator to multiply 2 fractions
CFraction operator *(const CFraction& f1,const CFraction& f2)
{
    return CFraction(f1.numerator()*f2.numerator(),f1.denominator()*f2.denominator());
}

int main()
{
    CFraction fraction1(3,4);

    cout << "Fraction: "<< fraction1.numerator() << "/" << fraction1.denominator() << endl;
    cout << "Decimal: " << static_cast<float>(fraction1) << endl;

    // Multiplication by function works very well
    CFraction result = multiplication(fraction1,2);

    // (ERROR) Compiller won't convert 2 to CFraction class
    CFraction result1 = fraction1*2;

    // Using manually covnerted integer - works again
    CFraction result2 = fraction1*static_cast<CFraction>(2);

    cout << "Multiplied by 2: " << static_cast<float>(result);

    getchar();
    return 0;
}

PS。問題があれば、MS Visual C+++ 2010 を使用しています。

4

4 に答える 4

3

問題は、あなたのクラスがas として宣言されておらず、 type の引数を 1 つ受け入れることができるFractionコンストラクターを持っていることです。したがって、このコンストラクタはコンパイラによって選択され、 aが必要になるたびにユーザー定義の暗黙的な変換シーケンスを実現できますが、 anが提供されます。explicitintFractionint

さらに、型Fractionには への変換演算子もあります。これにより、 aが必要になるたびfloatに暗黙的に に変換できますFractionが、 aが提供されます。floatfloatFraction

したがって、次の命令はあいまいです。

CFraction result1 = fraction1*2;

operator *コンパイラは、タイプのオブジェクトのオーバーロードを選択Fractionし、2 番目の引数 ( 2) を入力として渡すFractionコンストラクターを使用して a に変換するか、変換演算子を介して最初の引数を a に変換してから変換するかを認識しません。組み込みの を使用して、 aと an の間の乗算を実行します。Fraction2floatoperator *floatint

C++11 では、変換演算子を作成することを決定できますexplicit。これにより、あいまいさが回避されます。暗黙のうちに にfraction1変換することはできなくなります。そのため、コンパイラには、に変換して呼び出す2オプションしかありません。のオーバーロード。2Fractionoperator *

この場合、 からFractionへの変換を実行したい場合floatは、キャストを明示的に記述する必要があります。

float f = static_cast<float>(result1);

もう1つの選択肢はexplicit、変換演算子ではなくコンストラクターを作成することです。これFractionにより、整数に変換可能な単一の値が提供されたときにコンパイラーが a を暗黙的にインスタンス化できなくなります。

これにより、変換演算子を介してfraction1aに変換する唯一の選択肢がコンパイラに残されるという点で、上記の乗算自体のあいまいさが解決されます。floatただし、2 つの問題が発生します。

まず、次のように書くことができなくなります。

CFraction result = multiplication(fraction1, 2);

Fractionこれは、2 番目の引数から を作成しようとするためです2(引数としてmultiplication()2が必要Fractionsです)。代わりに、オブジェクトを明示的に構築する必要があります。

CFraction result = multiplication(fraction1, CFraction(2));

result1第二に、上記の元の乗算は機能しますが、(もう一度)暗黙の変換が必要になるため、の最終的なコピー初期化は機能しません。

したがって、コピーの初期化を次のように書き直す必要があります。

CFraction result1 = CFraction(fraction1*2);

または直接初期化として:

CFraction result1(fraction1*2);
于 2013-03-29T22:20:45.223 に答える
0

CFraction クラスで float への変換を提供するため、コンパイラには変換の選択肢があります。

CFraction result1 = fraction1*2;

CFractions で独自の演算子 * を使用するか、float と int で標準演算子 * を使用します。

C++11 を使用できる場合は、float 変換を明示的にマークできます。それ以外の場合は、「as_float」などの名前に変更してください。暗黙の変換はしばしば問題となるため、避けるのが最善です。

于 2013-03-29T22:33:39.437 に答える
0

テンプレートを使用して、コンパイラへの変換を残してください。

于 2013-03-30T18:37:30.860 に答える
0
    CFraction result2 = fraction1 * 2;

How you use a result has no effect on how it's computed, so this is just:

   fraction1 * 2

This is ambiguous. You could convert fraction1 to a float and multiply that by 2. You could convert 2 to a Fraction and then use operator*. The compiler has no idea which you want.

于 2013-03-29T22:21:50.143 に答える