Кажется, я не могу получить правильный результат для №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;
}
Вы хотите что-то большее:
Calculator operator+(const Calculator& c) const
{
return x + c.x;
}
но на самом деле не понимаю, что должен делать ваш член данных y
. Подумайте, вы должны избавиться от него и сделать x
private
.
return x + cx
и все должно работать.
Прежде всего, у вас есть элемент данных 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
.
Я действительно не понимаю перегрузку, так может кто-нибудь объяснить это мне, пожалуйста?
Оператор может быть перегружен как член класса или определение внешнего класса.
Рассмотрим этот код:
Calculator c1, c2, c_result;
c_result = c1 + c2;
operator +
имеет 3 'компоненты':
c1
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++.
g++ -Wall -g
). Научитесь использовать отладчик (gdb
). Всегда инициализируйте полеy
. И назовите свойy
(например, чтобыadd
) формальный параметр как-нибудь еще.