I'm sure that someone has asked this question before but I simply don't know what to search for. So I'm happy to remove this question as soon as someone points me to a similar one. I'm also happy to rename the questions if someone has a better suggestion :-)
I want to know if the following code is defined behavior by the standard or if this might be compiler/platform dependent:
struct A
{
virtual void f()
{
std::cout << "A::f()" << std::endl;
}
};
struct B : public A
{
// f() is not implemented here
};
struct C : public B
{
virtual void f() override
{
B::f(); // call f() of direct base class although it is not implemented there
std::cout << "C::f()" << std::endl;
}
};
int main()
{
A* pA = new C();
pA->f();
}
The output with Visual Studio 2017 and gcc 5.4.0 is:
A::f()
C::f()
Is it true that the compiler will search upwards in the hierarchy until it finds an implementation? Can you link to the C++ standard? I've tested it by making f() in A pure virtual and the linker nicely tells me that there is an unresolved symbol. Can I rely on that?
As I understand it using the scope operator like B::f() always calls the non-virtual version. So there is no polymorphism happening ever, is it?
Edit: The print statements where misleading, replaced "B::f()" with "C::f()".
The dynamic type of the pointer
A* pA = new C();
is C *
.
So the virtual function in the class C is called
struct C : public B
{
virtual void f() override
{
B::f(); // call f() of direct base class although it is not implemented there
std::cout << "B::f()" << std::endl;
}
};
The class B does not redefine the virtual function of the base class A. So in this statement
B::f(); // call f() of direct base class although it is not implemented there
the virtual function defined in the class A is called. That is the table of pointers to virtual functions of the class B contains the address of the function defined in the class A.
In this call
B::f();
there is access to the table of virtual functions of the class B and this table contains the address of the function definition in the class A because the function was not overriden in the class B.
From the C++ STandard (5.2.2 Function call)
- ...If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider (10.3) in the dynamic type of the object expression is called; such a call is referred to as a virtual function call. [