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