Неправильный вывод при перегрузке оператора «+» в программе «Калькулятор» для c ++

0

Кажется, я не могу получить правильный результат для №3. Выход должен быть 12, но я получаю хлам. Я действительно не понимаю перегрузку, так может кто-нибудь объяснить это мне, пожалуйста?

Я пробовал разные возвращения и другие вещи, но я не могу понять, что это правильно. Кто-нибудь, пожалуйста, объясните?

Я не получаю никаких ошибок, прямо сейчас, только отвал.

#include <iostream>

using namespace std;

class Calculator
{
private:

public:

    double total;
    double newNum;

    //default constructor
    Calculator()
    {
        total = 0;
    }

    double clear()
    {
        total = 0;
        return total;
    }

    void add(double num)
    {
        num += y;
    }

    void subtract(double num)
    {
        num -= y;
    }

    void multiply(double num)
    {
        total  *= num;
    }

    void divide (double num)
    {
        total /= num;
    }

    double display()
    {
        return total;
    }

    //parameterized constructor
    Calculator(double newNum)
    {
        x = newNum;
    }

    Calculator operator+(Calculator c)
    {
        return Calculator(y);
    }

};

int main() 
{
    Calculator mycalc;
    mycalc.clear();
    mycalc.add(4.52);
    mycalc.add(3.789);
    mycalc.divide(2.6);
    mycalc.multiply(3.12);
    mycalc.subtract(2.678);
    cout << mycalc.display() << endl;       // prints out "7.2928"
    mycalc.clear();
    mycalc.add(5.0);
    cout << mycalc.display() << endl;       // prints out "5"

    //advanced stuff #1: add a constructor
    Calculator calc1;
    cout << calc1.display() << endl;  //prints out 0

    //advanced stuff #2: add a parameterized constructor
    Calculator calc2(5);
    cout << calc2.display() << endl; //prints out 5

    //advanced stuff #3: Define calculator addition (overload the '+' operator)
    Calculator calc3(7);
    calc1 = calc2 + calc3;
    cout << calc1.display() << endl;  //prints out 12

    //advanced stuff #4: Create an 'undo' method for the calculator
//      mycalc.undo();
//      mycalc.undo();
//      cout << mycalc.display()<< endl;  //prints out 7.2928

    return 0;
}
  • 1
    Скомпилируйте все предупреждения и отладочную информацию ( g++ -Wall -g ). Научитесь использовать отладчик ( gdb ). Всегда инициализируйте поле y . И назовите свой y (например, чтобы add ) формальный параметр как-нибудь еще.
  • 1
    Ну, вы на самом деле ничего не добавляете ?
Показать ещё 2 комментария
Теги:
calculator
output
operator-keyword
overloading

3 ответа

1
Лучший ответ

Вы хотите что-то большее:

Calculator operator+(const Calculator& c) const
{
    return x + c.x;
}

но на самом деле не понимаю, что должен делать ваш член данных y. Подумайте, вы должны избавиться от него и сделать x private.

  • 0
    Просто return x + cx и все должно работать.
  • 0
    @JoachimPileborg да, спасибо. Это сработало
Показать ещё 3 комментария
2

Прежде всего, у вас есть элемент данных y который никогда не инициализируется. Поэтому, когда вы это делаете:

return Calculator(y);

Вы возвращаете Calculator созданный с использованием значения мусора. Но это выглядит очень странным оператором добавления. Вы, вероятно, хотите что-то вроде

Calculator operator+(const Calculator& c) const
{
  Calculator tmp = c;
  tmp.add(x);
  return tmp;
}

Лучшим подходом является перегрузка += и выражение оператора как нечлена. Это обеспечивает симметричность между LHS и RHS. Это особенно важно в вашем случае, потому что вам нужны неявные преобразования из числовых типов:

Calculator operator+(const Calculator& lhs, const Calculator& rhs)
{
  Calculator tmp = lhs;
  tmp += rhs;
  return tmp;
}

Это приводит 3.14 + c действительным выражениям c + 3.14 и 3.14 + c, где c - экземпляр Calculator.

0

Я действительно не понимаю перегрузку, так может кто-нибудь объяснить это мне, пожалуйста?

Оператор может быть перегружен как член класса или определение внешнего класса.

Рассмотрим этот код:

Calculator c1, c2, c_result;
c_result = c1 + c2;

operator + имеет 3 'компоненты':

  • input: первый операнд: c1
  • input: второй операнд: c2
  • вывод: результат c_result

Перегрузка оператора похожа на функцию с двумя операндами в качестве аргументов, а результат - на возврат. С этого момента я буду использовать переменную оператора перегрузку и функцию/класс.


Когда вы перегружаетесь как член класса:

class Calculator {
  private:
    int x;
  public:
    Calculator operator+(const Calculator &c) const {
//  ^^^^^^^^^^           ^^^^^^^^^^^^^^^^^^^^
//  ^ result ^           ^^ second operand ^^

       Calculator result;
       result.x = x + c.x; // equivalent to result.x = this->x + c.x;
       return result;
    }
};

Здесь второй операнд передается функции как единственный параметр, а функция return используется как результат оператора. Но что происходит с первым операндом? Ну, так как это метод класса, этот метод вызывается в первом объекте операнда, поэтому код с самого начала

c_result = c1 + c2;

эквивалентно (становится):

c_result = c1.operator+(c2);

Здесь вы можете ясно видеть, что оператор вызывается как метод объекта c1.

Таким образом, первый операнд фактически является объектом, на который вызывается перегрузка.

Подводить итоги:

  • первым операндом является this объект метода (перегрузка оператора).
  • второй операнд является единственным аргументом метода.
  • результатом является возврат метода.

Когда вы перегружаетесь как определение внешнего класса:

class Calculator {
  private:
    int x;
  public:
    friend Calculator operator+(const Calculator &c1, const Calculator &c2);
};

Calculator operator+(const Calculator &c1, const Calculator &c2) {
//^^^^^^^^           ^^^^^^^^^^^^^^^^^^^^
//^result^           ^^ first operand ^^   ^^ second operand ^^

    Calculator result;
    result.x = c1.x + c2.x;
    return result;
}

Два операнда передаются как два аргумента функции, а возврат используется в результате оператора. Итак, код:

c_result = c1 + c2;

эквивалентно (становится):

c_result = operator+(c1, c2);

Здесь вы можете ясно видеть, что оператор вызывается как функция.

friend декларация необходима, чтобы функция (которая не является методом класса) может обращаться к частному члену x класса Calculator.

Подводить итоги:

  • первым операндом является первый параметр функции (перегрузка оператора).
  • второй операнд является вторым параметром функции.
  • результатом является возврат функции.

Теперь позвольте немного поговорить о классификаторах типов. Поскольку вы имеете дело с классами, наилучшей практикой является передача параметров по ссылке, а не по значению, чтобы весь объект не копировался в область метода/функции. Но со ссылками вы можете (случайно) изменить исходный объект, поэтому вам нужно сделать их const:

c_result = c1 + c2;

Оператор + не изменяет c1 или c2, поэтому любые ссылки на них должны быть const:

Calculator operator+(const Calculator &c) const {

Аргумент (второй операнд) имеет тип const Calculator &.
Вы указываете, что первый операнд является постоянным, добавляя const к методу класса. Это указывает, что this объект (объект, на который вызван метод, в данном случае первый операнд) не будет изменен методом.

Calculator operator+(const Calculator &c1, const Calculator &c2) {

Оба параметра, т.е. оба операнда являются постоянными ссылками.

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


Надеюсь это поможет. Это относится ко всем операторам. Вот список, в котором вы можете увидеть, какой прототип имеет каждого оператора в C++.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню