John
John

Reputation: 746

C++ inheritance and method overloading confusion

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

Answers (4)

bellum
bellum

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

Kerrek SB
Kerrek SB

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

Mankarse
Mankarse

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

Dietmar K&#252;hl
Dietmar K&#252;hl

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

Related Questions