成员函数 cv-qualifier 重载

当通过对该类的 cv 限定引用访问类中的函数时,它们可以重载; 这最常用于 const 的重载,但也可以用于 volatileconst volatile 的重载。这是因为所有非静态成员函数都将 this 作为隐藏参数,cv-qualifiers 应用于该参数。这最常用于 const 的超载,但也可用于 volatileconst volatile

这是必要的,因为只有当成员函数至少与调用它的实例一样符合 cv 限定时才能调用它。虽然非 const 实例可以同时调用 const 和非 const 成员,但 const 实例只能调用 const 成员。这允许函数根据调用实例的 cv 限定符具有不同的行为,并允许程序员通过不提供具有该限定符的版本来禁止不期望的 cv 限定符的函数。

具有一些基本的 print 方法的类可能会像这样重载:

#include <iostream>

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        void print()
        {
            std::cout << "int: " << i << std::endl;
        }

        void print() const
        {
            std::cout << "const int: " << i << std::endl;
        }

    protected:
        int i;
};

int main()
{
    Integer i{5};
    const Integer &ic = i;
    
    i.print(); // prints "int: 5"
    ic.print(); // prints "const int: 5"
}

这是 const 正确性的一个关键原则:通过将成员函数标记为 const,允许在 const 实例上调用它们,这反过来允许函数将实例作为 const 指针/引用(如果它们不需要修改它们)。这允许代码指定它是否通过将未修改的参数(如 const)和修改后的参数(不具有 cv-qualifiers)修改为状态,从而使代码更安全且更易读。

class ConstCorrect 
{
  public:
    void good_func() const 
    {
        std::cout << "I care not whether the instance is const." << std::endl;
    }

    void bad_func() 
    {
        std::cout << "I can only be called on non-const, non-volatile instances." << std::endl;
    }
};

void i_change_no_state(const ConstCorrect& cc) 
{
    std::cout << "I can take either a const or a non-const ConstCorrect." << std::endl;
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Error.  Can only be called from non-const instance.
}

void const_incorrect_func(ConstCorrect& cc) 
{
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Good.  Can only be called from non-const instance.
}

这种情况的一个常见用法是将访问器声明为 const,将 mutator 声明为非 const

const 成员函数中不能修改类成员。如果你确实需要修改某个成员,例如锁定 std::mutex,则可以将其声明为 mutable

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        int get() const
        {
            std::lock_guard<std::mutex> lock{mut};
            return i;
        }

        void set(int i_)
        {
            std::lock_guard<std::mutex> lock{mut};
            i = i_;
        }

    protected:
        int i;
        mutable std::mutex mut;
};