Невозможно назначить нестатический элемент данных внутри функции-члена const
Я пытаюсь использовать std::unordered_set
в качестве хеш-таблицы для хранения многих CreditCard
"S. CreditCard
и другой класс CardDatabase
определяются следующим образом:
class CreditCard {
private:
string cardHolder;
unsigned long long cardNumber;
int limit;
int balance;
public:
CreditCard(string in_cardHolder, string in_cardNumber, int in_limit) {
cardHolder = in_cardHolder;
cardNumber = stoll(in_cardNumber);
limit = in_limit;
balance = 0;
}
void ChangeBalance(int amount) const {
balance += amount; // SECOND ERROR
}
};
class CardDatabase {
private:
unordered_set<CreditCard> cards;
unordered_set<CreditCard>::iterator iter;
public:
CardDatabase() { }
void AddCard(cardHolder, cardNumber, int limit) {
CreditCard tempCard = CreditCard(cardHolder, cardNumber, limit);
cards.insert(tempCard);
}
void Charge(string cardHolder, int chargeAmount) {
iter = cards.find(cardHolder);
iter->ChangeBalance(chargeAmount); // FIRST ERROR
}
}
Первоначально я получал следующую ошибку компиляции в FIRST ERROR
: Member function 'ChangeBalance' not viable: 'this' argument has type 'const CreditCard', but function is not marked const
, Итак, я добавил "const" к ChangeBalance
функция. Однако после этого я получаю следующую ошибку компиляции в SECOND ERROR
: Cannot assign to non-static member within const member function 'ChangeBalance'
,
Есть ли способ исправить эту ошибку без изменения balance
к статической переменной? Очевидно, важно, чтобы баланс был разным для каждого CreditCard
пример.
Любая помощь приветствуется.
РЕДАКТИРОВАТЬ:
Спасибо всем за ваши быстрые ответы. Я чувствую, что должен кое-что прояснить. Я уже добавил правильную хэш-функциональность в другом месте моего кода:
namespace std {
template <>
struct hash<CreditCard> {
size_t operator()(const CreditCard& cc) const
{
return hash<string>()(cc.GetCardHolder());
}
}
}
Кроме того, код, который я выложил первоначально, взят из гораздо большей базы кода, и я сначала не удалил все необходимые элементы пространства имен перед публикацией вопроса. Мои извинения за путаницу.
5 ответов
Члены unordered_set
являются постоянными и не могут быть изменены, когда они находятся в unordered_set
, по умолчанию. Вы пытаетесь изменить объекты в наборе, и компилятор правильно говорит вам, что вы не можете этого сделать.
Единственно возможный способ сделать это правильно (объясняется только в образовательных целях, потому что это плохой дизайн класса):
Явно объявить отдельные поля, которые могут быть изменены таким образом, как
mutable
,Используйте пользовательскую хеш-функцию с вашим
unordered_set
и хеш-функция должна исключать значение изменяемых полей из значения вычисляемого хеша.
В противном случае изменение содержимого объекта в наборе, очевидно, изменит его хеш-значение, что приведет к неопределенному поведению.
Опять же, это объясняется только в информационных целях. Это не хороший дизайн класса.
Чистым способом сделать это было бы назначить уникальный идентификатор каждому CreditCard
(вы знаете, как номер кредитной карты?), и использовать обычный std::map
, чтобы посмотреть вверх CreditCard
с их числом.
Это не подходит для ChangeBalance
иметь постоянную семантику. По самой природе своего имени вы модифицируете объект. Сделайте функцию неконстантной.
void ChangeBalance(int amount) {
balance += amount;
}
Другая проблема заключается в том, что вы неправильно вызвали свою функцию. Вы должны вместо этого сделать это:
iter->ChangeBalance(chargeAmount);
Я упомяну, что есть случаи, когда вы хотите изменить значения в const- объекте, и есть mutable
модификатор типа для этого. Не используйте его для решения вашей текущей ошибки, однако!
void ChangeBalance(int amount)
не должно быть const
- это изменение объекта.
Проблема раньше в итераторе: cards.find
возвращает const
объект, поэтому вы не можете изменить его.
Способ решить это, чтобы сделать ваш cards
установить набор указателей на карты, а не на карты; или использовать другой способ найти подходящую карту
Быстро и свободно играть с синтаксисом C++ в этом коде, Хосс. Множество ошибок ждут за углом
Первая ошибка:
iter->CreditCard::ChangeBalance(chargeAmount);
должно быть
iter->ChangeBalance(chargeAmount);
Прямой неверный синтаксис, который, вероятно, является результатом сбоев из-за ошибок, вызванных unordered_set
понятия не имею, как хешировать CreditCard
, Прочитайте это: Как я могу использовать unordered_set? Это сказало, unordered_set
Вероятно, не правильное решение для этой работы. std::map<std::string, CreditCard>
выглядит больше на точку.
Использование неправильного решения для устранения вышеуказанной проблемы приводит к
Вторая ошибка:
void ChangeBalance(int amount) const
const
метод означает, что метод не может изменить состояние объекта. в ChangeBalance
balance += amount;
пытается изменить состояние объекта путем обновления переменной-члена.
Кроме того, компилятор будет ненавидеть CreditCard::
в этом:
CreditCard::CreditCard(string in_cardHolder, string in_cardNumber, int in_limit) {
cardHolder = in_cardHolder;
cardNumber = stoll(in_cardNumber);
limit = in_limit;
balance = 0;
}
Другое решение — сделать «баланс» статическим элементом.
class CreditCard {
private:
string cardHolder;
unsigned long long cardNumber;
int limit;
static int balance;
....
}
А затем инициализируйте его в файле cpp
int CreditCard::balance = 0;
Этот код может быть не очень безопасным. Но это может быть одним из обходных путей.