3

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;
}
2
  • 1
    C++ isnt doing anything. Its you who is doing it Commented Nov 11, 2012 at 14:56
  • 1
    This is pretty much the opposite of a minimal example. We don't need a demonstration of what you do understand - just an example of what you don't. Commented Nov 11, 2012 at 15:03

4 Answers 4

3

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*).

Sign up to request clarification or add additional context in comments.

2 Comments

Correct me if I'm wrong, but what I'm gathering is this: The compiler looks at the pointer type, which is of Y1. So it goes into the class Y1, and finds which f() matches best. Then uses the type of the object that Y1 is pointing to, Y2, and calls the method in Y2 that has the same signature as the one it's decided on in Y1?
@user1137940: Yes, that's what's happening if the first step finds a virtual function. I think this is what I said in my answer, too.
1

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.

Comments

1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.