คลาส Rational Number ของฉันใช้ += พร้อมอาร์กิวเมนต์แบบยาวได้อย่างไร ในเมื่อฉันโอเวอร์โหลดมันเพื่อยอมรับอาร์กิวเมนต์ประเภท Rational เท่านั้น

ฉันได้ติดตั้ง operator+= (เหตุผล) ในไฟล์การใช้งานของฉันแล้ว แต่ฉันสังเกตเห็นโดยบังเอิญว่า Rational+= long long ใช้งานได้ แม้ว่าฉันจะไม่ได้ใช้ฟังก์ชันนั้นก็ตาม

ฟังก์ชั่นที่เกี่ยวข้องของ main ของฉันคือเมื่อฉันใช้ 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 โดยปริยาย สร้าง Constructor ตัวที่สองของคุณ explicit เพื่อป้องกันไม่ให้สิ่งนั้นเกิดขึ้น   -  person Resurrection    schedule 03.03.2017
comment
ไม่สามารถกำหนด += ในรูปของ + และ = ได้ใช่ไหม คุณกำหนด long long โอเวอร์โหลดเป็น + ก็น่าจะใช้อันนั้นอยู่..   -  person Carcigenicate    schedule 03.03.2017
comment
@Carcigenicate ไม่ การโอเวอร์โหลดตัวดำเนินการ C ++ ไม่ทำงานเช่นนั้น + และ += เป็นตัวดำเนินการสองตัวที่แตกต่างกัน และไม่มีวิธีใดที่จะกำหนดโดยปริยายโดยใช้อีกตัวหนึ่งได้ สามารถทำได้ (และบ่อยครั้ง) สามารถทำได้ด้วยตนเอง แต่ไม่ได้เป็นส่วนหนึ่งของภาษา   -  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
@แองจี้ อุ๊ย.. ขอขอบคุณสำหรับการชี้แจง.   -  person Carcigenicate    schedule 03.03.2017


คำตอบ (3)


หากต้องการตอบคำถามของคุณเกี่ยวกับ +=: ดูที่ตัวสร้างนี้:

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

ตัวสร้างไม่ได้ตกแต่งด้วยคีย์เวิร์ด explicit ซึ่งหมายความว่าสามารถใช้สำหรับการแปลงโดยนัยได้

จะเกิดอะไรขึ้นเมื่อคุณมีนิพจน์ += ที่มีตัวถูกดำเนินการประเภท Rational และ long long ก็คือคอมไพเลอร์ค้นหาคำจำกัดความทั้งหมดของ operator += จากนั้นดูว่ามีรายการใดบ้างที่สามารถยอมรับประเภทตัวถูกดำเนินการได้ (นั่นคือความละเอียดเกินพิกัด)

หากไม่มีรายการที่ตรงกันโดยตรง (ซึ่งไม่มีในกรณีของคุณ) ระบบจะพยายามดูว่า Conversion โดยนัยใดๆ สามารถทำให้ตรงกันได้หรือไม่ += ของคุณต้องใช้ 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


เกี่ยวกับคำขออื่นของคุณ

การปรับปรุง/ข้อมูลเชิงลึกอื่น ๆ ในงานจะได้รับการชื่นชมอย่างมาก

นั่นไม่อยู่ในหัวข้อสำหรับ Stack Overflow จริงๆ สมมติว่าโค้ดของคุณใช้งานได้ คุณอาจได้รับความคิดเห็นที่น่าสนใจเกี่ยวกับ การตรวจสอบโค้ด

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