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
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]
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.
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.
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.