21

Вопрос по inheritance, c++ – Как реализовано множественное наследование в C ++?

Одиночное наследование легко реализовать. Например, в C наследование может быть смоделировано как:

struct Base { int a; }
struct Descendant { Base parent; int b; }

Но с множественным наследованием компилятор должен расположить несколько родителей внутри вновь созданного класса. Как это сделать?

Возникающая проблема: родители должны быть устроены в AB или BA, или, может быть, даже как-то иначе? И потом, если я сделаю бросок:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;

Компилятор должен решить, следует ли изменить исходный указатель или нет. Подобные хитрости требуются от виртуалов.

  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Альтернативная ссылка:citeseerx.ist.psu.edu/viewdoc/…

    от
  • После прочтения обоих, в зависимости от того, что вы после. Это (Stroustrup's one) довольно подробно и охватывает теорию. Тот, предложенныйNemanja ниже (MSDN's one) является более простым и охватывает реальную реализацию.

    от
  • Обе ссылки сейчас мертвы, ноusenix.org/publications/compsystems/1989/fall_stroustrup.pdf работает для меня.

    от
  • @Dario: в этой статье рассматриваются проблемы перегрузки в множественном наследовании, но не содержится ничего о компоновке объектов и приведении объектов в C ++.

    от mmmmmmmm
  • Вы C симуляция забывает указатель VTable (детали реализации).

    от Martin York
  • @Martin York: если в классах нет виртуальных методов, указатель v-таблицы отсутствует.

    от mmmmmmmm
  • en.wikipedia.org/wiki/Diamond_problem

    от Dario
7 ответов
  • 10

    Следующая статья от создателя C ++ описывает возможную реализацию множ

    ественного наследования:

    Множественное наследование для C ++ - Бьярне Страуструп

  • 5

    Там было

    эта довольно старая статья MSDN о том, как это было реализовано в VC ++.

  • 1

    Это интересная проблема

    которая на самом деле не специфична для C ++. Вещи усложняются также, когда у вас есть язык с множественной диспетчеризацией и множественным наследованием (например, CLOS).

    Люди уже отметили, что существуют разные способы решения проблемы. В этом контексте вам может быть интересно прочитать о мета-объектных протоколах (MOP) ...

  • 0

    Я выполнил простой эксперимент:

    class BaseA { int a; };
    class BaseB { int b; };
    class Descendant : public BaseA, BaseB {};
    int main() {
            Descendant d;
            BaseB * b = (BaseB*) &d;
            Descendant *d2 = (Descendant *) b;
            printf("Descendant: %p, casted BaseB: %p, casted back Descendant: %p\n", &d, b, d2);
    }
    

    Выход:

    Descendant: 0xbfc0e3e0, casted BaseB: 0xbfc0e3e4, casted back Descendant: 0xbfc0e3e0
    

    Хорошо понимать, что статическое приведение не всегда означает «изменение типа без касания содержимого». (Хорошо, когда типы данных не соответствуют друг другу, тогда также будет вмешательство в контент, но это другая ситуация IMO).

  • 0

    Это полностью зависит от компилятора

    как это делается, но я полагаю, что это обычно делается через иерархическую структуру vtables.

  • 1

    Родители расположены в том порядке, в котором они указаны:

    class Derived : A, B {} // A comes first, then B
    
    class Derived : B, A {} // B comes first, then A
    

    Ваш второй случай обрабатывается в зависимости от компилятора. Один общий способ использует указатели, которые больше, чем размер указателя платформы, для хранения дополнительных данных.

  • 5

    And then, if I do a cast:

    SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;
    

    The compiler must consider whether to alter or not the original pointer. Similar tricky things with virtuals.

    С невирусным наследованием это менее сложно, чем вы думаете - в момент компиляции приведения компилятор знает точную компоновку производного класса (в конце концов компилятор выполнил макет). Обычно все, что происходит, это фиксированное смещение (которое может быть нулевым для одного из базовых классов) добавляется / вычитается из указателя производного класса.

    Вирусное наследование может быть немного сложнее - это может включать получение смещения от vtbl (или аналогичного).

    Книга Стэна Липпмана,& quot; Внутри объектной модели C ++ & quot; есть очень хорошие описания того, как этот материал может (и часто действительно) работает.