Виртуальная табличная схема С++ для MI (множественное наследование)

Посмотрите на следующий код на С++

class Base1 {  
public:  
    Base1();  
    virtual ~Base1();  
    virtual void speakClearly();  
    virtual Base1 *clone() const;  
protected:  
    float data_Base1;  
};  

class Base2 {  
public:  
    Base2();  
    virtual ~Base2();  
    virtual void mumble();  
    virtual Base2 *clone() const;  
protected:  
    float data_Base2;  
};  

class Derived : public Base1, public Base2 {  
public:  
    Derived();  
    virtual ~Derived();  
    virtual Derived *clone() const;  
protected:  
    float data_Derived;  
}; 

Внутри "Объектной модели С++" 4.2 говорится, что виртуальная табличная раскладка классов Base1, Base2 и Derived выглядит так: enter image description here

enter image description here

Мой вопрос:

Виртуальная таблица SubObject Base1 класса Derived содержит Base2::mumble.Почему? Я знаю, что Derived class поделился этой виртуальной таблицей с Base1, поэтому я думаю, что функция Base2 не должна появляться здесь. Может ли кто-нибудь сказать мне, почему? спасибо.

Ответы

Ответ 1

Хорошо, прежде всего, я напомню всем, что дизайн решения для реализации полиморфизма является решением ABI за пределами Стандарта. Например, MSVC и Itanium ABI (за ними следуют gcc, clang, icc,...) имеют разные способы реализации этого.

С этой точки зрения, я думаю, что это оптимизация для поиска.

Всякий раз, когда у вас есть объект Derived (или один из его потомков) и ищет элемент mumble, вам не нужно действительно обнаруживать подобъект Base2, но может непосредственно действовать из подобъекта Base1 адрес которого совпадает с подобъектом Derived, поэтому не задействована арифметика).

Ответ 2

Во время выполнения, когда вы получаете:

    Base2 b2;
    Base1* b1_ptr = (Base1*)&b2;
    b1_ptr->mumble();    // will call Base2::mumble(), this is the reason.

Затем необходимо вызвать Base2:: mumble()! Позаботьтесь о том, чтобы mumble() был единственным виртуальным методом, который был переоценен в иерархии. (Даже, вы можете думать, что clone() слишком сильно переопределен, но он возвращает другой тип среди классов, тогда это еще одна подпись).