Trouble with const/non-const overload resolution

不羁岁月 提交于 2019-12-03 12:18:37

问题


I have a class that looks something like this:

class ClassA
{
  public:
    float Get(int num) const;
  protected:
    float& Get(int num);
}

Outside of the class, I call the Get() function.

float foo = classAInstance.Get(i);

I expect this to call the public version, but instead Visual Studio errors out:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA'

When commenting out the protected overload and removing all references to it, the code compiles.

Why does the compiler try to use the inaccessible member when an accessible one is available? Is there an accepted way to force the compiler to choose the correct overload? Is there a reference to the resolution rules for member functions somewhere?


回答1:


It's true, overload resolution takes place before accessibility checks. Section 13.3 of the standard ([over.match]) says:

Overload resolution is a mechanism for selecting the best function to call given a list of expressions that are to be the arguments of the call and a set of candidate functions that can be called based on the context of the call. The selection criteria for the best function are the number of arguments, how well the arguments match the parameter-type-list of the candidate function, how well (for non-static member functions) the object matches the implicit object parameter, and certain other properties of the candidate function. [ Note: The function selected by overload resolution is not guaranteed to be appropriate for the context. Other restrictions, such as the accessibility of the function, can make its use in the calling context ill-formed. — end note ]

The usual fix is to give the public and protected functions different names.


Note, this is useful sometimes, example:

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

Note that name_ref will only be read from, so it's appropriate to make it const. However, const references can bind to temporaries, and binding name_ref to a temporary would be a dangling reference, resulting in undefined behavior in do_something_with_name_ref().

Blah c("Kablooey!"); // would be undefined behavior
                     // the constructor overload makes this a compile error

The private constructor overload prevents a temporary std::string from being implicitly constructed and bound.




回答2:


Overload resolution is done first, and access check later.

If you have both a const and a non-const overload, this is resolved by the constness of the object the function is called for.



来源:https://stackoverflow.com/questions/6239630/trouble-with-const-non-const-overload-resolution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!