1

Code -

#include<iostream>
              
    using namespace std;
         
class P {
    public:
    void print()  { cout <<" Inside P"; }
    };
          
class Q : public P {
    public:
    void print() { cout <<" Inside Q"; }
    };
         
class Q2: public P {
    public:
    void print2() { cout <<" Inside Q2"; }
    };
          
class R: public Q2, public Q { };
          
int main(void)
{
    R r; 
    r.print(); // error: request for member ‘print’ is ambiguous
    return 0;
}

Expected behavior: No ambiguous call on 3rd line in main.

Actual behavior: Ambiguous call on 3rd line in main

Rationale: I expected class Q to hide the print() function of class P. I would expect an ambiguous call error when Q2 has the same function name as R or Q (or even P?). But I deliberately changed the function name in Q2 to 'print2' to avoid this error. This error goes away when I remove 'Q2' as parent class of R. Is this happening because 'Q2' inherits 'print' from 'P'?

Note: I know similar questions have been asked on data hiding for regular inheritance and ambiguous calls in case of inheritance from multiple classes, but this case is sort of a mixture of two, and I did not find any specific answers.

  • Does this answer your question? [How does virtual inheritance solve the "diamond" (multiple inheritance) ambiguity?](https://stackoverflow.com/questions/2659116/how-does-virtual-inheritance-solve-the-diamond-multiple-inheritance-ambiguit) – Stephen Newell Apr 17 '22 at 18:16
  • @StephenNewell it does help me understand why this is happening, but my comment to Sam Varshavchik's answer below further confuses me. I thought that print was being inherited form P through Q2, but when I changed the access modified of print in P to private, I still get the same error (AFAIK, private components of a parent class should not be inherited?) – Speedracer1702 Apr 17 '22 at 18:40

2 Answers2

1

I expected class Q to hide the print() function of class P

This has nothing to do with Q hiding the superclass's print().

Q2 inherits from P, and therefore inherits print().

class R: public Q2, public Q { };

print() is inherited from both Q2 and from Q. Whether they turn out to be the same or different methods is immaterial. The point is that it is ambigous which print() method R.print() resolves to.

would expect an ambiguous call error when Q2 has the same function name

But it does. It inherits it.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
1

This is very typical C++ Diamond problem with multiple inheritance.

what you have is when R call the print functions he does not know from which print to cal.

you can solve this by helping the R class object to specify which print you want to call.

below modification can illustrate this.

#include<iostream>
              
    using namespace std;
         
class P {
    public:
    void print()  { cout <<" Inside P\n"; }
    };
          
class Q : public P {
    public:
    void print() { cout <<" Inside Q\n"; }
    };
         
class Q2: public P {
    public:
    void print2() { cout <<" Inside Q2\n"; }
    };
          
class R: public Q2, public Q { };
          
int main(void)
{
    R r; 
    r.Q::print(); 
    r.Q2::print();
    // r.P::print();  ambiguous base call.
    // r.print();     ambiguous member
    return 0;
}
Anton K
  • 109
  • 6
  • Thanks! I knew about using the scope resolution operator as a workaround, but didn't realize the effect of the implicit inheritance of member functions from P to Q2. – Speedracer1702 Apr 17 '22 at 22:50