Reputation: 746
I'm sorry this is so contrived, but it relates to a homework problem. I understand why everything happens, except the line I commented. Can someone please explain to me why C++ is doing what it's doing?
Thanks
#include <iostream>
using namespace std;
class X0 {};
class X1: public X0 {};
class X2: public X1 {};
class Y1
{
public:
virtual void f(int v) { cout << "Y1(int)" << endl; }
virtual void f(const X0 *x) { cout << "Y1(X0)" << endl; }
virtual void f(const X1 *x) { cout << "Y1(X1)" << endl; }
};
class Y2: public Y1
{
public:
virtual void f(const X0 *x) { cout << "Y2(X0)" << endl; }
virtual void f(const X1 *x) { cout << "Y2(X1)" << endl; }
virtual void f(const X2 *x) { cout << "Y2(X2)" << endl; }
};
int main(int argc, char * argv[])
{
X2 x2; X2 *X2Pointer = &x2;
Y2 y2; Y1 *Y1Pointer = &y2;
cout << "What is about to happen?" << endl;
//Y1 pointer points to a Y2 object.
//The Y2 class, upon being given an X2 pointer, should print Y2(X2)
Y1Pointer->f(X2Pointer);
cout << "Why did I just print Y2(X1)" << endl;
return 0;
}
Upvotes: 3
Views: 137
Reputation: 3710
As other mentioned the problem is function hiding. But what you can do is write inside Y1 line using Y0::f;
to get result that you want.
Upvotes: 0
Reputation: 477580
The class Y1
has no overload that consumes an X2 *
. The best match for the function call Y1Pointer->f(X2Pointer)
is Y1::f(X1 const *)
. The fact that the actual object to which your Y1Pointer
points is more derived than Y1
does not matter, as it has nothing to do with which overload is selected.
Upvotes: 1
Reputation: 40643
Overload resolution is determined on the basis of the static types that are involved.
Y1Pointer->f(X2Pointer)
matches to Y1::f(const X1 *x)
, because the static type of Y1Pointer
is Y1*
, and so Y1::f(const X1 *x)
is the best match for a call to f
with a X2*
parameter.
Y1::f(const X1 *x)
is virtual, so the actual function that is called is determined by the dynamic type. Y1Pointer
points to a Y2
, so the Y2
version of f(const X1 *x)
is invoked.
Upvotes: 1
Reputation: 154035
The class Y1
exposes these there overload of f()
:
class Y1: public Y0 {
public:
virtual void f(int v) { cout << "Y1(int)" << endl; }
virtual void f(const X0 *x) { cout << "Y1(X0)" << endl; }
virtual void f(const X1 *x) { cout << "Y1(X1)" << endl; }
// ...
};
All other methods called f()
inherited from Y0
are hidden. That is, when you call
Y1Pointer->f(X2Pointer);
the compiler does overload resolution on the three overloads of f()
and comes to the conclusion that f(const X1*)
is the best match and calls this function. As it turns out, this is a virtual
function, overridden by Y2
and it, thus, invokes Y2::f(const X1*)
.
Upvotes: 3