我有一个看起来像这样的课程:
class ClassA
{
public:
float Get(int num) const;
protected:
float& Get(int num);
}
在课堂之外,我调用了Get()函数。
float foo = classAInstance.Get(i);
我希望这可以调用公共版本,但是Visual Studio会出错:
error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA'
当注释掉受保护的重载并删除对它的所有引用时,代码将编译。
为什么编译器会在可访问的成员可用时尝试使用不可访问的成员?是否有一种可以接受的方法来强制编译器选择正确的重载?是否有参考成员函数的解决规则?
答案 0 :(得分:7)
确实,在进行可访问性检查之前会发生重载决策。标准的第13.3节([over.match]
)说:
重载解析是一种机制,用于在给定表达式列表的情况下选择要调用的最佳函数 作为调用的参数和一组可以根据上下文调用的候选函数 电话。最佳函数的选择标准是参数的数量,参数的好坏程度 匹配候选函数的参数类型列表,如何(对于非静态成员函数) object匹配隐式对象参数以及候选函数的某些其他属性。 [ 注意: 重载决策选择的功能不能保证适合上下文。其他 限制(例如函数的可访问性)可以使其在调用上下文中的使用不正确。 - 结束说明]
通常的解决方法是为公共和受保护的函数提供不同的名称。
注意,这有时很有用,例如:
class Blah
{
const std::string& name_ref;
Blah(const char*) = delete;
public:
Blah(const std::string& name) : name_ref(name) {}
void do_something_with_name_ref() const;
};
std::string s = "Blam";
Blah b(s); // ok
请注意,name_ref
只会被读取,因此适合const
。但是,const
引用可以绑定到临时对象,将name_ref
绑定到临时引用将是一个悬空引用,导致do_something_with_name_ref()
中的未定义行为。
Blah c("Kablooey!"); // would be undefined behavior
// the constructor overload makes this a compile error
私有构造函数重载可以防止临时构造和绑定临时std::string
。
答案 1 :(得分:5)
首先完成过载分辨率,稍后进行访问检查。
如果同时具有const和非const重载,则通过调用该函数的对象的常量来解决此问题。