Как работает перегрузка оператора и почему она не работает в моем случае? - PullRequest
0 голосов
/ 23 февраля 2019

Мне была предоставлена ​​функция драйвера, которая должна демонстрировать результаты перегрузки операторов с использованием комплексных чисел.Прочитав некоторое время о перегрузке, мне удалось написать код таким образом, чтобы он успешно компилировался, однако где-то по пути правильные значения не выводились программой.

Из того, что я понимаю, перегрузка по сути работает как функция.Объекты передаются, и «функция» может затем выполнить арифметику / что угодно с ней и вернуть новый объект.Хотя я немного растерялся, так как перегрузка знает, какие значения передаются.Например, в моем случае я перегружал операторы «+» и «=», чтобы добавить два комплексных числа в форме «x = y + z».Когда компилятор встречает символ «=», я предполагаю, что он просто пропускает все, что находится слева и справа, и пропускает их?То же самое с "+".В этом случае он будет передавать «y», поскольку это объект слева, а «z», потому что это объект справа?

Вот мой текущий «сложный» класс, который включает определения перегрузки.

class Complex {

private:
double realPart;
double imaginaryPart;

public:
// friends
friend ostream & operator<<(ostream &out, const Complex &c);
friend istream & operator>>(istream &in,  Complex &c);

// constructors
Complex()
{
    realPart = 0;
    imaginaryPart = 0;
}

Complex(double real)
{
    realPart = real;
    imaginaryPart = 0;
}

Complex(double real, double imaginary)
{
    realPart = real;
    imaginaryPart = imaginary;
}
// end of constructors

// + overloading
Complex operator+(Complex const &c)
{
    Complex Add;
    Add.realPart = realPart + c.realPart;
    Add.imaginaryPart = imaginaryPart + c.imaginaryPart;
    return Add;
}

// - overloading
Complex operator-(Complex const &c)
{
    Complex Subtract;
    Subtract.realPart = realPart - c.realPart;
    Subtract.imaginaryPart = imaginaryPart - c.imaginaryPart;
    return Subtract;
}

// * overloading
Complex operator*(Complex const &c)
{
    Complex Multiply;
    Multiply.realPart = (realPart * c.realPart) - (imaginaryPart * c.imaginaryPart);
    Multiply.imaginaryPart = (realPart * c.imaginaryPart) - (imaginaryPart * c.realPart);
    return Multiply;
}

// = overloading
Complex operator=(Complex const &c)
{
    Complex Assignment;
    Assignment.realPart = realPart;
    Assignment.imaginaryPart = imaginaryPart;
    return Assignment;
}

// == overloading
bool operator==(Complex const &c)
{
    Complex Compare;
    if (Compare.realPart == realPart && Compare.imaginaryPart == imaginaryPart)
    {
        return true;
    }
    else
    {
        return false;
    }
}

    // != overloading
bool operator!=(Complex const &c)
{
    Complex NotEqual;
    if (NotEqual.realPart == realPart && NotEqual.imaginaryPart == imaginaryPart)
    {
        return false;
    }
    else
    {
        return true;
    }
}

};

// << overloading
ostream& operator<<(ostream& out, const Complex &c)
{
    out << c.realPart;
    if (c.imaginaryPart >= 0)
    {
        out << " + " << c.imaginaryPart << "i" << endl;
    }
    else
    {
        out << " - " << fabs (c.imaginaryPart) << "i" << endl;
    }

    return out;
}

// >> overloading
istream& operator>>(istream &in, Complex &c)
{
    in >> c.realPart;
    in >> c.imaginaryPart;
    return in;
}

А вот программа драйвера:

int main()
{
    for (double i = 1; i < 10; ++ i)
    {
        Complex y{i * 2.7, i + 3.2};
        Complex z{i * 6, i + 8.3};

        Complex x;
        Complex k;

        std::cout << "Enter a complex number in the form: (a, b)\n? ";
        std::cin >> k; // demonstrating overloaded >>
        std::cout << "x: " << x << "\ny: " << y << "\nz: " << z << "\nk: " << k << '\n'; // demonstrating overloaded <<

        x = y + z; // demonstrating overloaded + and =
        std::cout << "\nx = y + z:\n" << x << " = " << y << " + " << z << '\n';
        x = y - z; // demonstrating overloaded - and =
        std::cout << "\nx = y - z:\n" << x << " = " << y << " - " << z << '\n';
        x = y * z; // demonstrating overloaded * and =
        std::cout << "\nx = y * z:\n" << x << " = " << y << " * " << z << "\n\n";

        if (x != k)
        { // demonstrating overloaded !=
            std::cout << x << " != " << k << '\n';
        }

        std::cout << '\n';
        x = k;

        if (x == k)
        {
            // demonstrating overloaded ==
            std::cout << x << " == " << k << '\n';
        }

        std::cout << std::endl;
}
}

При запуске проблема, похоже, связана с объектом "x".Ввод «5 2» будет по-прежнему выводить «x: 0 + 0i». Это наводит меня на мысль, что проблема заключается в перегрузке «=» или операторах потока.Тем не менее, я не могу понять, почему ничего не происходит.

Есть ли ошибка в том, как я построил определение перегрузки "=", как мне кажется, или это может быть что-то большее, чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

operator=() неверен: пользователь Yakk - Adam уже показал вам, как это исправить.Чтобы вы поняли, почему это неправильно и что делает return *this;давайте посмотрим на вашу исходную функцию:

Complex operator=(Complex const &c) {
    Complex Assignment;
    Assignment.realPart = realPart;
    Assignment.imaginaryPart = imaginaryPart;
    return Assignment;
}

Здесь ваша подпись принимает константную ссылку на другой Complex объект, эта часть верна.Ваш тип возвращаемого значения - Complex объект, это по сути неправильно, потому что вы не хотите возвращать копию объекта.Целью здесь является выполнение задания.Это означает, что вы должны внести изменения в исходный экземпляр LHS.

В выражении A = B + C;A считается LHS экземпляром.Здесь вы хотите присвоить выражение (B + C), которые оба являются RHS значениями.

Итак, когда Yakk - Adam показал вам, как это исправить:

Complex& operator=(Complex const &c) {
  realPart = c.realPart;
  imaginaryPart = c.imaginaryPart;
  return *this;
}

Одно из различий здесь заключается в том, что тип возвращаемого значения теперь Referenceк определенному объекту, а не к копии объекта.

Другое отличие состоит в том, что нет необходимости создавать локальную временную копию, как это было в исходной версии:

Complex Assignment; // this is not needed

Удалив его из operator=(), он просто заменил следующие строки кода:

// Assignment.realPart = realPart; // To
realPart = c.realPart;
// Assignment.imaginaryPart = imaginaryPart; // To
imaginaryPart = c.imaginaryPart;

Здесь вы используете членов класса напрямую и присваиваете им значение, котороепринадлежит другому или c, который передается оператору.

Затем, наконец, вернуть ваш экземпляр LHS с обновленным значением;это где вы должны вернуть разыменованный указатель.

Что означает *this?Указатель this является специальным указателем, который принадлежит всем типам class и struct.Например, в любой момент, когда у вас есть объект класса:

class Foo {
public:
    int bar { 10 };

    void addFive();
}; 

Вы можете использовать этот указатель непосредственно в ваших функциях-членах:

void Foo::addFive() {
    this->bar += 5; // same as below  (this) belongs to this particular instance.
    // bar += 5;        
}

Относительно вашего operator=();так как вы возвращаетесь на reference, вы не можете просто return this.Это вернет указатель this.Мы не хотим указатель на объект, как мы хотим ссылку на объект;поэтому мы должны задержать указатель this, вернув *this.

Надеюсь, это поможет вам разобраться.

0 голосов
/ 23 февраля 2019

Ваш = неправ;он должен вернуть *this.

Complex& operator=(Complex const &c)
{
  realPart = c.realPart;
  imaginaryPart = c.imaginaryPart;
  return *this;
}

Исправьте это, и большинство остальных выглядит вменяемым.

...