27
class C
{
public:
    void foo() const {}
private:
    void foo() {}
};

int main()
{
    C c;
    c.foo();
}

MSVC 2013 doesn't like this:

> error C2248: 'C::foo' : cannot access private member declared in class 'C'

If I cast to a const reference, it works:

const_cast<C const &>(c).foo();

Why can't I call the const method on the nonconst object?

imz -- Ivan Zakharyaschev
  • 4,921
  • 6
  • 53
  • 104
japreiss
  • 11,111
  • 2
  • 40
  • 77

2 Answers2

24

The object is not const, so the non-const overload is a better match. Overload resolution happens before access checking. This ensures that overload resolution is not inadvertently changed by changing the access of a member function.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 18
    And the reasoning is that the designers felt it would be error prone to have lookup and resolution depend on access checking; changing a method from public to private could result in uses of that function silently switching to some other function without that being the intention. – bames53 Aug 14 '14 at 20:15
22

From the standard:

13.3.3 If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (Clause 11) in the context in which it is used, the program is ill-formed.

imreal
  • 10,178
  • 2
  • 32
  • 48
  • 12
    I.e. lookup semantics in C++ applies as if access checks did not exist. Then access checks are applied. Access checks do not affect visibility and choice, only permission. – Kaz Aug 14 '14 at 23:14
  • So code external to the class can break by adding a private member function. External code depends on class internals. – usr Aug 15 '14 at 10:29
  • @usr But you get a compiler error. If it weren't this way, code's behaviour could change silently when you change the access of a member function. – juanchopanza Aug 15 '14 at 12:53
  • @juanchopanza causing a compiler error is a breaking change. If C is in a library that library must be carefully naming its private members to not cause depending code to break when the library updates. – usr Aug 15 '14 at 12:55
  • 2
    @usr Changing the behaviour is also a breaking change. Better to fail early. But in real code you shouldn't have overloads with different access. – juanchopanza Aug 15 '14 at 12:59