C++ base class function call from last derived in

2019-09-05 15:58发布

I'm learning C++ and after having read and tested a lot about multiple inheritance, virtual inheritance/methods and diamond design I still have some problems to understand it till the end.

I'm in the diamond design pattern, where class B e C inherit virtual public A and D inherits public B, public C:

    A
  /   \
 B     C
  \   /
    D

All classes implement a private variable std::string _message that I initialize with the following string.

 "class-name instance"

Only Class A implements a virtual public display(void) const method too.

void     display(void) const{
     std::cout << this->_message << std::endl;
}

The main is:

D foo;
foo.display();

The output is:

A instance

However when I "inspect" the element debugging step by step with Xcode I see that inside the D instance I can correctly find a B, a C and A object (just one shared by B and C) with all the different _message correctly assigned.

What I'm doing wrong? Need I override the display() method in D class? But if so, which is the real point of multiple inheritance if I have to re-implements the same method in a derived class?

1条回答
Fickle 薄情
2楼-- · 2019-09-05 16:30

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.

查看更多
登录 后发表回答