Your question seems to not be related to the diamond pattern, but is generally about the inheritance model in C++. Most things in C++ are statically bound, so at compile time the compiler fixes what method or member of a certain name is used:
If you access a member of the implicit this
object or using a pointer or reference to an object, you will end up accessing a member of the class the pointer or reference has at compile time, no matter whether at runtime there is a derived-class object that has members of the same name. That's why they say you can not override but just shadow members in base classes when you define an equal named member in the derived class.
The same thing is true for non-virtual functions.
The only thing that behaves different is virtual functions. These functions can be overwritten in derived classes, and code that gets handed a pointer-to-base-class can virtual functions of the base class and end up executing implementations given in the derived class.
So the point of virtual functions is not to have the compiler reinterpret a certain function in the context of derived classes (as you seem to understand it), but to make it possible to replace a function in the base class by a different function in the derived class.
To go back to your motivation: If you want a display
function that prints a message that depends on the actual object type, the thing that is fixed is the printig, which doesn't need to be virtual. But you need a virtual function to obtain the object type. Like this:
#include <iostream>
#include <ostream>
class A {
public:
void display() { std::cout << get_message() << '\n'; }
virtual const char * get_message() { return "A instance"; }
};
class B : virtual public A {
public:
virtual const char * get_message() { return "B instance"; }
};
class C : virtual public A {
public:
virtual const char * get_message() { return "C instance"; }
};
class D : public B, public C {
public:
// virtual const char * get_message() { return B::get_message(); }
// virtual const char * get_message() { return C::get_message(); }
// virtual const char * get_message() { return "D instance"; }
};
int main(void)
{
D foo;
foo.display();
A* a_ptr = &foo;
a_ptr->display();
return 0;
}
The example as given will not compile (now this is due to the diamond pattern), because the compiler can not decide, what overrider of A::get_message()
, either B::get_message()
or C::get_message()
should be picked in D objects, you need to make one of the comments in D real code to declare the one-and-only get_message
for D, in which can re-use the existing functions.