const /非const重载决议的问题

the*_*der 11 c++ overloading visual-studio-2010 overload-resolution

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

class ClassA
{
  public:
    float Get(int num) const;
  protected:
    float& Get(int num);
}
Run Code Online (Sandbox Code Playgroud)

在课外,我调用了Get()函数.

float foo = classAInstance.Get(i);
Run Code Online (Sandbox Code Playgroud)

我希望这可以调用公共版本,但是Visual Studio会出错:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA'
Run Code Online (Sandbox Code Playgroud)

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

为什么编译器在可访问的成员可用时尝试使用不可访问的成员?是否有一种可以接受的方法来强制编译器选择正确的重载?在某处有成员函数的解决规则吗?

Ben*_*igt 9

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

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

通常的解决方法是为公共和受保护的函数提供不同的名称.


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

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
Run Code Online (Sandbox Code Playgroud)

请注意,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
Run Code Online (Sandbox Code Playgroud)

私有构造函数重载可防止临时std::string构造和绑定临时.


Bo *_*son 5

首先完成过载分辨率,稍后进行访问检查.

如果同时具有const和非const重载,则通过调用该函数的对象的常量来解决此问题.