gingi007
gingi007

Reputation: 117

virtual tables and inheritance c++

i have a question regarding calling a function with virtual methods and multiple inheritence. i have the following code:

#include<iostream>
using namespace std;
class A{};
class B:public A{};
class C:public B{};
class AA:public A{};
struct X
{
    void f(A*) { std::cout<< "X::f(A*)\n";}
    virtual void f(B*) { std::cout<< "X::f(B*)\n";}
    void f(C*) { std::cout<< "X::f(C*)\n";}
    virtual void f(C*) const { std::cout<< "const X::f(C*)\n";}
};
struct Y:public X {
    virtual void f(B*) { std::cout<< "Y::f(B*)\n";}
    void f(A*) { std::cout<< "Y::f(A*)\n";}
    virtual void f(C*) const { std::cout<< "const Y::f(C*)\n";}
};
int main() {   
    Y* y=new Y();
    y->f(new C);
}

I can't understand why this turns ambiguous and there are 2 candidates:

 Y::f(B*)
 Y::f(C*)

Upvotes: 2

Views: 90

Answers (3)

Potatoswatter
Potatoswatter

Reputation: 137770

For an overloading function to be selected, it has to be the "best" at accepting each individual argument, including the implicit argument that becomes this. Best is defined in terms of the least conversions needed to convert the argument (in the caller) to the parameter (in the callee).

virtual void f(C*) const agrees perfectly with an argument of type C*, but the const qualifier at the end requires that this be converted from a non-const Y* to a Y const *. This is what the compiler is complaining about. If you cast

static_cast< Y const * >( y )->f(new C);

The problem goes away (although this isn't immediately illustrative since the extra qualification disqualifies the other overloads).

Note that all the overloads in X aren't even checked. The name resolution which finds all the overloads to be considered starts at the derived class and proceeds up the inheritance branches until it finds a matching name, and then it stops. To merge functions from multiple classes into one overload set, use a using declaration inside Y, using X::f;.

The actual solution to this problem is probably to introduce more matching overloads without const qualifiers at the end, so the const qualification of the calling pointer doesn't play such an unintuitive role.

Upvotes: 4

user2249683
user2249683

Reputation:

Your overload for C is the only const member function. y is non const and all overloads of f are acceptable, hence the call is ambiguous.

Ways to resolve the ambiguity:

  • Add a non const overload for C
  • Make y const
  • Make the overloads for A and B const

Upvotes: 2

Blaz Bratanic
Blaz Bratanic

Reputation: 2279

void f(C*) { std::cout << "X::f(C*)\n"; } in base class is not visible due to name hiding.

use using X::f; in derived class, and it works as expected.

Upvotes: 0

Related Questions