Невозможно назначить нестатический элемент данных внутри функции-члена 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, по умолчанию. Вы пытаетесь изменить объекты в наборе, и компилятор правильно говорит вам, что вы не можете этого сделать.

Единственно возможный способ сделать это правильно (объясняется только в образовательных целях, потому что это плохой дизайн класса):

  1. Явно объявить отдельные поля, которые могут быть изменены таким образом, как mutable,

  2. Используйте пользовательскую хеш-функцию с вашим 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 метод означает, что метод не может изменить состояние объекта. в ChangeBalancebalance += 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;

Этот код может быть не очень безопасным. Но это может быть одним из обходных путей.

Другие вопросы по тегам