In C++, is a function automatically virtual if it

2019-01-14 12:21发布

问题:

I would expect that if foo is declared in class D, but not marked virtual, then the following code would call the implementation of foo in D (regardless of the dynamic type of d).

D& d = ...;
d.foo();

However, in the following program, that is not the case. Can anyone explain this? Is a method automatically virtual if it overrides a virtual function?

#include <iostream>

using namespace std;

class C {
public:
        virtual void foo() { cout << "C" << endl; }
};

class D : public C {
public:
        void foo() { cout << "D" << endl; }
};

class E : public D {
public:
        void foo() { cout << "E" << endl; }
};

int main(int argc, char **argv)
{
        E& e = *new E;
        D& d = *static_cast<D*>(&e);
        d.foo();
        return 0;
}

The output of the above program is:

E

回答1:

Standard 10.3.2 (class.virtual) says:

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides*

[Footnote: A function with the same name but a different parameter list (clause over) as a virtual function is not necessarily virtual and does not override. The use of the virtual specifier in the declaration of an overriding function is legal but redundant (has empty semantics). Access control (clause class.access) is not considered in determining overriding. --- end foonote]



回答2:

Quick answer may be no, but correct answer is yes

C++ doesn't know about function hiding, so overriding virtual function without virtual keyword marks that function virtual too.



回答3:

You are not creating any copy of the object of e and putting it in d. So d.foo() follows normal polymorphic behavior and calls derived class method. A method which is declared as virtual in the base class becomes automatically virtual in the derived class also.



回答4:

The output ("E") behaves exactly as one would expect it to behave.

The reason: The dynamic (i.e. runtime) type of that reference is E. You are doing a static upcast to D, but that does not change the actual type of the object of course.

That's the very idea behind virtual methods and dynamic dispatches: You see the behavior of the type you were instantiating, which is E, in this case.