11

我有一个看起来像这样的类:

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'

当注释掉受保护的重载并删除对它的所有引用时,代码会编译。

当一个可访问的成员可用时,为什么编译器会尝试使用不可访问的成员?是否有一种公认的方式来强制编译器选择正确的重载?是否在某处引用了成员函数的解析规则?

4

2 回答 2

9

确实,重载决议发生在可访问性检查之前。标准 ( ) 的第 13.3 节[over.match]说:

重载解析是一种机制,用于在给定作为调用参数的表达式列表和可以根据调用上下文调用的一组候选函数的情况下选择要调用的最佳函数。最佳函数的选择标准是参数的数量、参数与候选函数的参数类型列表的匹配程度、对象与隐式对象参数的匹配程度(对于非静态成员函数)以及某些其他候选函数的属性。[注意:重载决议选择的函数不能保证适合上下文。其他限制,例如函数的可访问性,可能使其在调用上下文中的使用格式不正确。——尾注]

通常的解决方法是为公共和受保护的函数赋予不同的名称。


请注意,这有时很有用,例如:

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构造和绑定。

于 2011-06-04T21:58:21.670 回答
5

重载解决首先完成,然后访问检查。

如果您同时具有 const 和非 const 重载,则这可以通过调用函数的对象的 const 来解决。

于 2011-06-04T21:58:33.827 回答