Reputation: 117
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
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
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:
Upvotes: 2
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