简体   繁体   中英

How does overload resolution work in the context of private modifier?

I am unable to understand the output of the following C++ snippet.

Should not objc.fn() call A 's fn() since B's fn() is private and should not be visible in C . However, the answer is: the call to fn() is ambiguous. How?

#include<iostream>
using namespace std;

class A{
  public:
   void fn() { cout << "1"; }
};
class B{
   void fn() { cout << "2"; }
};
class C: public A, public B {};

int main(){
  C objc;
  objc.fn();
  return 0;
}

According to the book C++ Templates: The Complete Guide Appendix B.1,

At a very high level, a call to a named function can be processed in the following way:

  1. The name is looked up to form an initial overload set.

  2. If necessary, this set is tweaked in various ways (for example, template deduction occurs).

  3. Any candidate that doesn't match the call at all (even after considering implicit conversions and default arguments) is eliminated from the overload set. This results in a set of so-called viable function candidates.

  4. Overload resolution is performed to find a best candidate. If there is one, it is selected; otherwise, the call is ambiguous.

  5. The selected candidate is checked. For example, if it is an inaccessible private member, a diagnostic is issued.

As you can see, the access authority is checked at last, so the call to fn() is ambiguous will be reported firstly at step #4.

Consider this:

class D {
    void fn1() {}
public:
    void fn2() {}
};

int main() {
    D d;
    d.fn2(); // Compiles fine
    d.fn1(); // Error: fn1 is private
}

Notice that the error for d.fn1() is about fn1 being private, not that fn1 is unknown or invisible in this scope. By the same token, B::fn is indeed visible in C .

We get this behavior because the compiler does name resolution the same for public and private members. Only after the name has been resolved does the accessibility check come into play.

It is the same for your case: Which fn do you mean? Only after you have answered that question can the compiler tell you if you have access to that fn or not.

As I suspected, this code gives an ambiguous reference and does not compile. As you have declared both functions with the same signature, the compiler doesn't know which of the functions to select, giving a complaint at compilation time.

$ make pru
g++     pru.cc   -o pru
pru.cc: In function ‘int main()’:
pru.cc:15:8: error: request for member ‘fn’ is ambiguous
pru.cc:9:9: error: candidates are: void B::fn()
pru.cc:6:9: error:                 void A::fn()
make: *** [pru] Error 1

I think you can select which function to use, placing the A::fn() selector. Even if, as it is the case in this example, one of the functions is private, you have two functions to select from (you could make the call from inside a B method and you'll get the same error ---in that case you have visibility to both methods).

The correct answer has already been given by @songyuanyao.
Checking access specifiers at the last was designed by the C++ Standard Committee .

Had it not been so, the following things would have occurred :

  • If one modifies their code in future and change the access specifier of their functions, it may break the compilation of the dependent classes.
  • More horrible yet, you may start calling a totally unrelated function, and would remain oblivious..!!

Let us assume that access specifiers prevent a function from participating in overload resolution, then :

class A{
  public:
    void fn() { cout << "1"; }
};
class B{
  void fn() { cout << "2"; }
};
class C: public A, public B {};

int main(){
  C objc;
  objc.fn(); // A::fn() is being invoked
  return 0;
}

Now we modify the code:

class A{
  void fn() { cout << "1"; }
};
class B{
  public:
    void fn() { cout << "2"; }
};

Nothing else has been touched, and suddenly

objc.fn(); // B::fn() is being invoked

The caller of your function has no idea that his underlying function is not the same anymore.
This is blasphemy !!

To prevent all such mishaps from happening, the Standard Committee took this design decision.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM