Bagaimana kelas Bilangan Rasional saya menggunakan += dengan argumen yang panjang padahal saya hanya membebaninya secara berlebihan untuk menerima argumen bertipe Rasional?

Saya telah menerapkan operator+= (Rasional) dalam file implementasi saya, namun secara tidak sengaja saya melihat bahwa Rational+= long long berfungsi, meskipun saya belum mengimplementasikan fungsi tersebut.

Fungsi yang relevan dari main saya adalah ketika saya menggunakan plusequals += num.

plusequals dinyatakan sebagai Rational plusequals dan num dinyatakan sebagai long long num. Keduanya diinisialisasi untuk memuat nilai dari input pengguna.

Apa yang menyebabkannya? Tampaknya bagi saya ini tidak akan berhasil, tetapi ternyata berhasil.

Ini file header saya:

#ifndef _RATIONAL_H_
#define _RATIONAL_H_

#include<iostream>


using namespace std;

class Rational
{
long long _p;
long long _q;

void simplify();

public:
Rational();
Rational (long long p, long long Q = 1);
Rational (const Rational&);

Rational& operator= (const Rational&);
Rational& operator+= (const Rational&);
Rational& operator-= (const Rational&);
Rational& operator*= (const Rational&);
Rational& operator/= (const Rational&);

friend ostream& operator<< (ostream&, const Rational&);
friend istream& operator>> (istream&, Rational&);

Rational operator+ (const Rational&);
Rational operator+ (long long) const;
friend Rational operator+ (long long, const Rational&);
Rational operator- (const Rational&);
Rational operator- (long long) const;
friend Rational operator- (long long, const Rational&);
Rational operator* (const Rational&);
Rational operator* (long long) const;
friend Rational operator* (long long, const Rational&);
Rational operator/ (const Rational&);
Rational operator/ (long long) const;
friend Rational operator/ (long long, const Rational&);

bool operator== (const Rational&) const;
bool operator== (long long) const;
friend bool operator== (long long, const Rational&);
bool operator!= (const Rational&) const;
bool operator!= (long long) const;
friend bool operator!= (long long, const Rational&);
bool operator> (const Rational&) const;
bool operator> (long long) const;
friend bool operator> (long long, const Rational&);
bool operator< (const Rational&) const;
bool operator< (long long) const;
friend bool operator< (long long, const Rational&);
bool operator>= (const Rational&) const;
bool operator>= (long long) const;
friend bool operator>= (long long, const Rational&);
bool operator<= (const Rational&) const;
bool operator<= (long long) const;
friend bool operator<= (long long, const Rational&);

Rational operator++ (int);
Rational operator-- (int);
Rational& operator++ ();
Rational& operator-- ();
Rational operator- () const;
Rational operator+ () const;

Rational pow (unsigned exp) const;
Rational inverse() const;
};

#endif

Dan berikut implementasinya:

#include "Rational.h"
#include <iostream>

void validate (long long, long long);

int gcd (long long, long long);

Rational::Rational()
{
    _p = 0;
    _q = 1;
}

Rational::Rational (long long p, long long Q)
{
    validate (p, Q);
    _p = p;
    _q = Q;
}

Rational::Rational (const Rational& rat)
{
    this->_p = rat._p;
    this->_q = rat._q;
}
void Rational::simplify()
{
    // Fixes negative denominators.
    if (_q < 0)
    {
        _p *= -1;
        _q *= -1;
    }

    // Simplifies Rational Numbers.
    int denom = gcd(_p, _q);
    _p /= denom;
    _q /= denom;

}

Rational& Rational::operator= (const Rational& rat)
{
    _p = rat._p;
    _q = rat._q;

    return *this;
}

Rational& Rational::operator+= (const Rational& rat)
{
    _p = ((_p * rat._q) + (_q * rat._p));
    _q *= rat._q;

    this->simplify();

    return *this;
}

Rational& Rational::operator-= (const Rational& rat)
{
    _p = ((_p * rat._q) - (_q * rat._p));
    _q *= rat._q;

    this->simplify();

    return *this;
}

Rational& Rational::operator*= (const Rational& rat)
{
    _p *= rat._p;
    _q *= rat._q;

    this->simplify();

    return *this;
}

Rational& Rational::operator/= (const Rational& rat)
{
    if (rat._p == 0)
    {
        throw "Division by zero not allowed";
    }
    _p *= rat._q;
    _q *= rat._p;

    this->simplify();

    return *this;
}

ostream& operator<< (ostream& os, const Rational& rat)
{
    os << rat._p << ":" << rat._q;

    return os;
}

istream& operator>> (istream& is, Rational& rat)
{
    long long p, q;

    is >> p >> q;
    validate(p, q);
    rat._p = p;
    rat._q = q;
    rat.simplify();

    return is;
}

Rational Rational::operator+ (const Rational& rat)
{
    Rational result(*this);

    result += rat;
    result.simplify();

    return result;
}

Rational Rational::operator+ (long long num) const
{
    Rational result(*this);
    Rational temp(num);

    result += temp;
    result.simplify();

    return result;
}

Rational operator+ (long long num, const Rational& rat)
{
    Rational result(num);
    result += rat;
    result.simplify();

    return result;
}

Rational Rational::operator- (const Rational& rat)
{
    Rational result(*this);

    result -= rat;
    result.simplify();

    return result;
}

Rational Rational::operator- (long long num) const
{
    Rational result(*this);
    Rational temp(num);

    result -= temp;
    result.simplify();

    return result;
}

Rational operator- (long long num, const Rational& rat)
{
    Rational result(num);
    result -= rat;
    result.simplify();

    return result;
}

Rational Rational::operator* (const Rational& rat)
{
    Rational result(*this);

    result *= rat;
    result.simplify();

    return result;
}

Rational Rational::operator* (long long num) const
{
    Rational result(*this);
    Rational temp(num);
    result *= temp;
    result.simplify();

    return result;
}

Rational operator* (long long num, const Rational& rat)
{
    Rational result(num);
    result *= rat;
    result.simplify();

    return result;
}

Rational Rational::operator/ (const Rational& rat)
{
    Rational result(*this);

    result /= rat;
    result.simplify();

    return result;
}

Rational Rational::operator/ (long long num) const
{
    Rational result(*this);
    Rational temp(num);

    result /= temp;
    result.simplify();

    return result;
}

Rational operator/ (long long num, const Rational& rat)
{
    Rational result(num);
    result /= rat;
    result.simplify();

    return result;
}

bool Rational::operator== (const Rational& rat) const
{
    bool result;

    if ((this->_p == rat._p) && (this->_q == rat._q))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

bool Rational::operator== (long long num) const
{
    bool result;
    Rational temp(num);

    result = (*this == temp);

    return result;
}

bool operator== (long long num, const Rational& rat)
{
    bool result;

    result = (rat == num);

    return result;
}

bool Rational::operator!= (const Rational& rat) const
{
    return !(*this == rat);
}

bool Rational::operator!= (long long num) const
{
    return !(*this == num);
}

bool operator!= (long long num, const Rational& rat)
{
    return !(num == rat);
}

bool Rational::operator> (const Rational& rat) const
{
    bool result;

    if ((this->_p / this->_q) > (rat._p / rat._q))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

bool Rational::operator> (long long num) const
{
    bool result;
    Rational temp(num);

    result = (*this > temp);

    return result;
}

bool operator> (long long num, const Rational& rat)
{
    bool result;

    result = (rat < num);

    return result;
}

bool Rational::operator< (const Rational& rat) const
{
    bool result;

    if (!(*this > rat) && !(*this == rat))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

bool Rational::operator< (long long num) const
{
    bool result;
    Rational temp(num);

    result = (*this < temp);

    return result;
}

bool operator< (long long num, const Rational& rat)
{
    bool result;

    result = (rat > num);

    return result;
}

bool Rational::operator>= (const Rational& rat) const
{
    bool result;

    if (!(*this < rat))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

bool Rational::operator>= (long long num) const
{
    bool result;
    Rational temp(num);

    result = (*this >= temp);

    return result;
}

bool operator>= (long long num, const Rational& rat)
{
    bool result;

    result = (rat <= num);

    return result;
}

bool Rational::operator<= (const Rational& rat) const
{
    bool result;

    if (!(*this > rat))
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

bool Rational::operator<= (long long num) const
{
    bool result;
    Rational temp(num);

    result = (*this <= temp);

    return result;
}

bool operator<= (long long num, const Rational& rat)
{
    bool result;

    result = (rat >= num);

    return result;
}

Rational Rational::operator++ (int) // Postfix
{
    Rational temp(*this);

    this->_p++;
    this->_q++;

    return temp;
}

Rational Rational::operator-- (int) // Postfix
{
    Rational temp(*this);

    this->_p--;
    this->_q--;

    return temp;
}

Rational& Rational::operator++()
{
    this->_p++;
    this->_q++;

    return *this;
}

Rational& Rational::operator--()
{
    this->_p--;
    this->_q--;

    return *this;
}

Rational Rational::operator-() const
{
    Rational temp(-(this->_p), (this->_q));

    return temp;
}

Rational Rational::operator+() const
{
    Rational temp(+(this->_p), +(this->_q));

    return temp;
}

Rational Rational::pow (unsigned exp) const
{
    Rational result(*this);
    Rational temp(*this);

    if (exp == 0)
    {
        result = 1;
    }
    else
    {
        for (unsigned i = 1; i < exp; i++)
        {
            result *= temp;
        }
    }

    return result;
}

Rational Rational::inverse() const
{
    Rational temp(this->_q, this->_p);

    return temp;
}

void validate(long long p, long long q)
{
    p++; // Supress error for unused value. Decided to keep value in parameter list to maintain clarity.
    if (q == 0)
    {
        throw "Zero Denominator";
    }
}

int gcd(long long p, long long q)
{
    // Euclid's Algorithm
    if (q == 0)
    {
        return p;
    }
    return gcd (q, p%q);
}

Dan sebagai tambahan, tes main() yang saya gunakan:

#include <string>
#include <iostream>
#include "Rational.h"

int main()
{
    while (true)
    {
        Rational rat1;
        Rational rat2;
        Rational rat3;
        long long num;
        unsigned exp;
        Rational power(rat1);
        string hello = "hello";

        // Get input
        try
        {
            cout << "Please enter a numerator and denominator separated by a space: ";
            cin >> rat1;
            cout << endl;
            cout << "Please enter a second numerator and denomintator seperated by a space: ";
            cin >> rat2;
            cout << endl;
            cout << "Please enter a numerator and denominator separated by a space for a third Rational number: ";
            cin >> rat3;
            cout << endl;
            cout << "Enter a number to use for arithmetic operations: ";
            cin >> num;
            cout << endl;
            cout << "Please enter a positive integer to use an exponent :";
            cin >> exp;
            cout << endl;
        }
        catch (char const* err)
        {
            cerr << err << " - Non-Zero denominators only ya big goon.\n";
        }

        cout << endl;

        cout << "You put: " << rat1 << " and: " << rat2 << endl;

        Rational plusequals (rat1);
        Rational minusequals (rat1);
        Rational timesequals (rat1);
        Rational divequals (rat1);

        plusequals += rat2;
        minusequals -= rat2;
        timesequals *= rat2;
        try
        {
            divequals /= rat2;
        }
        catch (const char* msg)
        {
            cerr << msg << endl;
        }

        cout << "+= : " << plusequals << "\n-= : " << minusequals << "\n*= : " << timesequals << "\n/= : " << divequals << endl;

        plusequals = rat1;
        minusequals = rat1;
        timesequals = rat1;
        divequals = rat1;

        plusequals += num;
        minusequals -= num;
        timesequals *= num;
        try
        {
            divequals /= num;
        }
        catch (const char* msg)
        {
            cerr << msg << endl;
        }

        cout << "\nRational = " << rat1<< ", num = " << num << "  :\n";
        cout << rat1 << " += " << num << ": " << plusequals << endl << rat1 << " -= " << num << ": " << minusequals << endl << rat1 <<" *= " << num << ": " << timesequals << endl << rat1 << " /= " << num << ": " << divequals << endl;

        plusequals = rat1;
        minusequals = rat1;
        timesequals = rat1;
        divequals = rat1;

        plusequals += rat3;
        minusequals -= rat3;
        timesequals *= rat3;
        try
        {
            divequals /= rat3;
        }
        catch (const char* msg)
        {
            cerr << msg << endl;
        }

        cout << "\nRational = " << rat1<< ", Rational = " << rat3 << "  :\n";
        cout << rat1 << " += " << rat3 << ": " << plusequals << endl << rat1 << " -= " << rat3 << ": " << minusequals << endl << rat1 << " *= " << rat3 << ": " << timesequals << endl << rat1 << " /= " << rat3 << ": " << divequals << endl;


        power = rat1.pow(exp);
        cout << endl << rat1 << " raised to the power of " << exp << " : ";
        cout << power << endl;

        cout << "The multiplicative inverse of " << rat1 << " is " << rat1.inverse() << endl;

        // Comparison
        cout << endl << endl;
        if (rat1 == rat2)
        {
            cout << rat1 << " = " << rat2 << endl;
        }
        if (rat1 != rat2)
        {
            cout << rat1 << " != " << rat2 << endl;
        }
        if (rat1 <= rat2)
        {
            cout << rat1 << " <= " << rat2 << endl;
        }
        if (rat1 >= rat2)
        {
            cout << rat1 << " >= " << rat2 << endl;
        }
        if (rat1 < rat2)
        {
            cout << rat1 << " < " << rat2 << endl;
        }
        if (rat1 > rat2)
        {
            cout << rat1 << " > " << rat2 << endl;
        }
    }
}

Juga, saya harus mencatat bahwa saya tahu saya tidak boleh berada using namespace std; di file header saya... tetapi kami diharuskan untuk menyalin header langsung dari profesor kami. Dia juga bersikeras agar kami menggunakan gaya braket yang saya gunakan dalam proyek khusus ini, yang menurut saya jelek tapi memang begitulah adanya. Dia sangat khusus. Namun, perbaikan/wawasan lainnya terhadap tugas ini akan sangat dihargai.


person Joseph Morgan    schedule 03.03.2017    source sumber
comment
Anda harus mencoba mengurangi hanya kode yang relevan di sini. 90% tidak relevan dengan masalah. Atau, paling tidak, rangkum bagian-bagian yang relevan di atas.   -  person Carcigenicate    schedule 03.03.2017
comment
Anda mungkin telah long long Anda secara implisit dikonversi ke Rational. Buat konstruktor kedua Anda explicit untuk mencegah hal itu terjadi.   -  person Resurrection    schedule 03.03.2017
comment
Tidak bisakah += didefinisikan dalam bentuk + dan =? Anda menetapkan long long kelebihan beban +. Mungkin menggunakan itu.   -  person Carcigenicate    schedule 03.03.2017
comment
@Carcigenicate Tidak. Kelebihan operator C++ tidak berfungsi seperti itu. + dan += adalah dua operator berbeda dan tidak ada cara untuk secara implisit mendefinisikan salah satu operator menggunakan operator lainnya. Ini bisa (dan sering kali) dilakukan secara manual, tapi itu bukan bagian dari bahasanya.   -  person Angew is no longer proud of SO    schedule 03.03.2017
comment
Terkait: stackoverflow.com/questions/15077466/   -  person Baum mit Augen    schedule 03.03.2017
comment
Kemungkinan duplikat: stackoverflow.com/questions/4766964/ Semakin hangat...   -  person Baum mit Augen    schedule 03.03.2017
comment
@Angew Ups. Terimakasih atas klarifikasinya.   -  person Carcigenicate    schedule 03.03.2017


Jawaban (3)


Untuk menjawab pertanyaan Anda tentang +=: lihat konstruktor ini:

Rational (long long p, long long Q = 1);

Konstruktor tidak dihiasi dengan kata kunci explicit, yang berarti dapat digunakan untuk konversi implisit.

Apa yang terjadi ketika Anda memiliki ekspresi += dengan operan bertipe Rational dan long long adalah kompiler mencari semua definisi operator += dan kemudian mencari apakah ada di antara definisi tersebut yang dapat menerima tipe operan (itulah resolusi kelebihan beban).

Jika tidak ada yang cocok secara langsung (dalam kasus Anda, tidak ada yang cocok), maka ia akan mencoba melihat apakah ada konversi implisit yang dapat membuatnya cocok. += Anda memerlukan Rational di kedua sisi. Operasi sisi kiri sudah menjadi Rational, tidak diperlukan apa pun di sana. Sisi kanannya adalah long long, tetapi ada konversi implisit dari long long ke Rational (melalui konstruktor). Jadi kompiler mengeluarkan kode untuk membuat Rational sementara dari long long, dan kemudian memasukkan Rational sementara ini ke operator += Anda.

Anda dapat mencegah konversi implisit ini dengan menandai konstruktor sebagai explicit, tetapi menurut saya Anda salah jika melakukannya. Lagi pula, apakah ada masalah dengan penulisan "1/2 + 1 = 3/2"? Kita tidak perlu menulis "1/2 + 1/1".

Konversi implisit antar angka berguna. 3.14 + 1 adalah C++ yang benar-benar valid (dan masuk akal) berkat konversi implisit dari int ke double.


Mengenai permintaan Anda yang lain,

Namun, perbaikan/wawasan lainnya terhadap tugas ini akan sangat dihargai.

itu bukan topik yang tepat untuk Stack Overflow. Dengan asumsi kode Anda berfungsi, Anda mungkin mendapatkan masukan menarik di Tinjauan Kode.

person Angew is no longer proud of SO    schedule 03.03.2017
comment
Terima kasih banyak atas balasan Anda dan mengoreksi permintaan perbaikan saya. Saya tidak mengetahui Tinjauan Kode, saya pasti akan memeriksanya. - person Joseph Morgan; 16.03.2017

Rational_object += (long long)_object

berfungsi karena Anda memiliki konstruktor konversi.

Rational (long long p, long long Q = 1);

Yang memungkinkan kompiler secara implisit mengonversi long long menjadi Rational. Anda dapat mencegah perilaku ini dengan menandai konstruktor tersebut explicit

person WhiZTiM    schedule 03.03.2017

long long secara implisit diubah menjadi Rational karena kelas Anda memiliki Rational (long long p, long long Q = 1); konstruktor. Anda dapat menggunakan kata kunci eksplisit untuk menghindari transmisi secara implisit.

person JustRufus    schedule 03.03.2017