Calling overrided virtual function instead of over

2019-07-15 04:01发布

问题:

Say i have this part of code:

#include<iostream>
using namespace std;
class A {
public:
    virtual int f(const A& other) const { return 1; }
};
class B : public A {
public:
    int f(const A& other) const { return 2; }
    virtual int f(const B& other) const { return 3; }
};

void go(const A& a, const A& a1, const B& b) {
    cout << a1.f(a) << endl; //Prints 2
    cout << a1.f(a1) << endl; //Prints 2
    cout << a1.f(b) << endl; //Prints 2
}
int main() {
    go(A(), B(), B());
    system("pause");
    return 0;
}

I can understand why the first two will print 2. But I cannot understand why the last print is also 2. Why doesn't it prefers the overloaded function in B?

I already looked at this and this but I couldn't manage to understand from these.

回答1:

int B::f(const B& other) const doesn't override int A::f(const A& other) const because the parameter type is not the same. Then it won't be called via calling f() on reference of the base class A.

If some member function vf is declared as virtual in a class Base, and some class Derived, which is derived, directly or indirectly, from Base, has a declaration for member function with the same

name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers 

Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).

If you use override specifier (since C++11) compiler will generate the error.

class B : public A {
public:
    int f(const A& other) const { return 2; }
    virtual int f(const B& other) const override { return 3; }
};

Such as Clang:

source_file.cpp:10:17: error: 'f' marked 'override' but does not override any member functions
    virtual int f(const B& other) const override { return 3; }
                ^

If you add an overload for it in the base class, you might get what you want. Note that a forward declaration of class B will be needed.

class B;
class A {
public:
    virtual int f(const A& other) const { return 1; }
    virtual int f(const B& other) const { return 1; }
};

LIVE



回答2:

It's easy, really. You're calling f on an object with static type A. A has only one f, so there's only one entry in the vtable for that function. Overload resolution takes place compile-time. The overload will only be resolved if you call it on an object whose static type is B



回答3:

The confusion comes in that your:

int f(const A& other) const { return 2; }

line is actually virtual also and is overriding your line:

virtual int f(const A& other) const { return 1; }

Meanwhile, the line:

virtual int f(const B& other) const { return 3; }

ends up being completely ignored because everything matches to the "return 1" line, then follows polymorphically up the chain to the "return 2" line. As the other poster said, the const B portion means it won't match the polymorphic method call.

As an aside: If you're getting a 2 on the first line, I'm suspicious of undesired stack behavior. I'd expect a 1. Perhaps try allocating like this:

A a1;
B b1, b2;

go(a1, b1, b2);