无法分配给 const 成员函数中的非静态数据成员

Cannot assign to non-static data member within const member function

我正在尝试使用 std::unordered_set 作为散列 table 来存储许多 CreditCardCreditCard和另一个classCardDatabase定义如下:

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());
        }
    }
}

此外,我最初粘贴的代码来自一个更大的代码库,在发布问题之前我没有删除所有必要的命名空间内容。对于造成的混乱,我深表歉意。

ChangeBalance 具有 const 语义是不合适的。就其名称的本质而言,您正在修改对象。使函数非常量。

void ChangeBalance(int amount) {
    balance += amount;
}

另一个问题是你没有正确调用你的函数。你应该这样做:

iter->ChangeBalance(chargeAmount);

我会提到在某些情况下您想要修改 const 对象中的值,并且有一个 mutable 类型修饰符。但是,不要使用它来解决您当前的错误!

void ChangeBalance(int amount) 不应该是 const - 它正在改变对象。

问题出在迭代器之前:cards.find returns 一个 const 对象,因此您不能更改它。

解决这个问题的方法是让您的 cards 设置一组指向卡片的指针,而不是卡片;或使用其他方式查找匹配的卡片

unordered_set 的成员是常量,一旦进入 unordered_set,默认情况下就无法更改。您正在尝试更改集合中的对象,编译器正确地告诉您不能这样做。

正确执行此操作的唯一可能方法(仅出于教育目的进行解释,因为这是糟糕的 class 设计):

  1. 明确声明可以通过这种方式修改的各个字段为mutable

  2. 在您的 unordered_set 中使用自定义哈希函数,哈希函数必须从计算的哈希值中排除可变字段的值。

否则,修改集合中对象的内容,显然会改变其哈希值,这将导致未定义的行为。

再次说明,这仅供参考。这不是一个好的 class 设计。

最简单的方法是为每个 CreditCard 分配一个唯一标识符(你知道,比如信用卡号?),然后使用普通的 std::map 来查找CreditCard他们的号码。

Hoss,在该代码中随意使用 C++ 语法。大量错误等待在拐角处

第一个错误:

iter->CreditCard::ChangeBalance(chargeAmount);

应该是

iter->ChangeBalance(chargeAmount);

由于 unordered_set 不知道如何对 CreditCard 进行散列而导致的错误,可能会导致直接错误的语法。读一读:How do I use unordered_set? That said, unordered_set is probably not the right solution for this job. std::map<std::string, CreditCard> 看起来更准确。

使用错误的解决方案解决上述问题导致

第二个错误:

void ChangeBalance(int amount) const
方法上的

const 表示该方法不能更改对象的状态。 in 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;

此代码可能不是很安全。但这可能是解决方法之一。