Как мой класс Rational Number использует += с длинным длинным аргументом, когда я только перегрузил его, чтобы он принимал аргумент типа Rational?

Я реализовал operator+= (Rational) в своем файле реализации, но случайно заметил, что Rational+= long long работает, хотя я не реализовал эту конкретную функцию.

Соответствующая функция моего основного - это когда я использую plusequals += num.

plusequals объявлен как Rational plusequals, а num объявлен как long long num. Оба инициализируются, чтобы содержать значение, введенное пользователем.

Что дает? Мне казалось, что это не должно работать, но это работает.

Вот мой заголовочный файл:

#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

А вот и реализация:

#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);
}

И на всякий случай тест main(), который я использую:

#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;
        }
    }
}

Кроме того, я должен отметить, что я знаю, что не должен быть using namespace std; в моих файлах заголовков... но мы должны скопировать заголовок непосредственно от нашего профессора. Он также настаивает на том, чтобы мы использовали стиль скобок, который я использую в этом конкретном проекте, который я считаю уродливым, но это то, что есть. Он очень особенный. Тем не менее, любые другие улучшения/понимание задания будут высоко оценены.


person Joseph Morgan    schedule 03.03.2017    source источник
comment
Вы должны попытаться сократить только соответствующий код здесь. 90% не имеет отношения к проблеме. Или, по крайней мере, суммируйте соответствующие биты вверху.   -  person Carcigenicate    schedule 03.03.2017
comment
Возможно, ваш long long неявно преобразован в Rational. Сделайте свой второй конструктор explicit, чтобы этого не произошло.   -  person Resurrection    schedule 03.03.2017
comment
Нельзя ли += определить через + и =? Вы определили long long перегрузку +. Это, вероятно, использует это.   -  person Carcigenicate    schedule 03.03.2017
comment
@Carcigenicate Нет. Перегрузка операторов С++ так не работает. + и += — это два разных оператора, и невозможно неявно определить один с помощью другого. Это можно (и часто) сделать вручную, но это не является частью языка.   -  person Angew is no longer proud of SO    schedule 03.03.2017
comment
Связано: stackoverflow.com/questions/15077466/   -  person Baum mit Augen    schedule 03.03.2017
comment
Возможный дубликат: stackoverflow.com/questions/4766964/ Становится теплее...   -  person Baum mit Augen    schedule 03.03.2017
comment
@Angew Упс. Благодарю за разъяснение.   -  person Carcigenicate    schedule 03.03.2017


Ответы (3)


Чтобы ответить на ваш вопрос о +=: посмотрите на этот конструктор:

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

Конструктор не украшен ключевым словом explicit, что означает, что его можно использовать для неявных преобразований.

Что происходит, когда у вас есть выражение += с операндами типа Rational и long long, так это то, что компилятор ищет все определения operator +=, а затем проверяет, может ли какое-либо из них принять типы операндов (это разрешение перегрузки).

Если ни один из них не соответствует напрямую (в вашем случае это не так), он попытается выяснить, могут ли какие-либо неявные преобразования привести к их совпадению. Ваш += требует Rational с обеих сторон. Левосторонняя операция уже Rational, ничего там не надо. Правая часть — long long, но существует неявное преобразование из long long в Rational (через конструктор). Итак, компилятор выдает код для создания временного Rational из long long, а затем передает этот временный Rational в ваш operator +=.

Вы можете предотвратить эти неявные преобразования, пометив конструктор как explicit, но я думаю, что вы сделаете это неправильно. В конце концов, есть ли проблема написать «1/2 + 1 = 3/2»? Нам не нужно писать «1/2 + 1/1».

Полезны неявные преобразования между числами. 3.14 + 1 является вполне допустимым C++ (и вполне разумным) благодаря неявному преобразованию из int в double.


Что касается вашего другого запроса,

Тем не менее, любые другие улучшения/понимание задания будут высоко оценены.

это не совсем по теме переполнения стека. Предполагая, что ваш код работает, вы можете получить интересные отзывы на Code Review.

person Angew is no longer proud of SO    schedule 03.03.2017
comment
Большое спасибо за ваш ответ и исправление меня в моем запросе на улучшение. Не знал о Code Review, обязательно посмотрю. - person Joseph Morgan; 16.03.2017

Rational_object += (long long)_object

работает, потому что у вас есть преобразующий конструктор.

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

Что позволяет компилятору неявно преобразовывать long long в Rational. Вы можете предотвратить такое поведение, пометив такой конструктор explicit

person WhiZTiM    schedule 03.03.2017

long long неявно преобразуется в Rational, потому что в вашем классе есть конструктор Rational (long long p, long long Q = 1);. Вы можете использовать явное ключевое слово, чтобы избежать неявного приведения.

person JustRufus    schedule 03.03.2017