简体   繁体   中英

C++ polymorphism function matching

I have the code bellow with chain inheritance with virtual function and it prints:

D ptr
E

So what is the algorithm for the function matching, my guess is it's matching the closest father class? But &e basically is of type A*,B*,D* why this even compiles and is it good practice to use this property?

#include <iostream>

using namespace std;

class A {
    public:
        virtual void f(){cout<<"A";};
};

class B :public A {
    public:
    virtual void f() {
        cout<<"B";
    }
};

class D : public B {
    public:
    virtual void f() {
        cout<<"D";
    }
};

class E : public D {
    public:
    virtual void f() {
        cout<<"E";
    }
};

void f(D *sth) {
    cout<<"D ptr"<<endl;
    sth->f();
}

void f(B *sth) {
    cout<<"B ptr"<<endl;
    sth->f();
}

void f(A *sth) {
    cout<<"A ptr"<<endl;
    sth->f();
}

int main() {
    E e;
    f(&e);
}

I will try to break down your example as best as I can:

int main() {
    E e;    // declare object of Class E
    f(&e);  // run f() function and pass it the address of E
}

Ok simple enough - you declared an object of Class E and then ran a function on it. Now the global f() function has been overloaded three times to accept pointers to the address of a D object, B object, or A object. Since all of these take objects higher up on the inheritance tree, any will work for a class E object. The compiler will choose the function for the most derived class. In this case, the void f(D *sth) function gets selected.

void f(D *sth) {
    cout<<"D ptr"<<endl; // "D ptr" printed to screen
    sth->f();            // Take original pointer to class E object and 
                         // run its own class method f() on it
}

Then looking at the class definition for E, we will see why E gets printed:

class E : public D {
    public:
    virtual void f() {
        cout<<"E";
    }
};

If you were to comment out the void f(D *sth) function, the compiler would instead select the void f(B *sth) function resulting in the output "B ptr" and "E". If you were to instead comment out the global f() function for A and B objects and then tried to run void f(D *sth) on a B object, it would not compile because the compiler can only convert objects up an inheritance tree, not down it.

As Phil1970 commented, this structure is generally frowned upon as it relies on global functions having knowledge of the inheritance tree.

It should have given you an undefined behavior or ambiguity. Different compiler versions can give different outcomes so you better don't rely on your results :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM