Асимметричный виртуальный алмаз Inheritance в C ++ - PullRequest
5 голосов
/ 07 августа 2009

Итак, у меня есть эта идея, и я думаю, что это в принципе невозможно реализовать в C ++ ... но я хочу спросить. Я прочитал главу 15 Страуструпа и не получил свой ответ, и я не думаю, что миллиард других вопросов о наследственных алмазах отвечает на этот вопрос, поэтому я задаю здесь.

Вопрос в том, что происходит, когда вы наследуете от двух базовых классов, которые совместно используют общий базовый класс, но фактически только один из двух наследует его. Например:

class CommonBase { ... };

class BaseA : CommonBase { ... };

class BaseB : virtual CommonBase { ... };

class Derived : BaseA, BaseB { ... };

Причина, по которой я хочу это сделать, заключается в том, что я пытаюсь расширить существующую библиотеку без необходимости перекомпилировать всю библиотеку (не хочу открывать эту банку с червями). Уже существует цепочка наследования, которую я хотел бы изменить. В основном как то так (извините, ascii art)

    LibBase
         | \
         |  \ 
         |   MyBase
         |     |
         |     |
 LibDerived    |
         | \   |
         |  \  |
         |   MyDerived
         |     |
LibDerived2    |
         | \   |
         |  \  |
         |   MyDerived2
         |     |
LibDerived3    |
         | \   |
         |  \  |
         |   MyDerived3
         |     |
LibConcrete    |
           \   |
            MyConcrete

Получить картину? Я хочу, чтобы объект каждого из классов "My" был объектом класса, который они по существу заменяют, но я хочу, чтобы следующий класс в диаграмме наследования использовал реализацию переопределенного метода из "My "базовый класс, но все остальные методы из классов библиотеки. Классы библиотеки не наследуются виртуально, поэтому это так

class LibDerived : LibBase

Но если я заставлю мой класс наследовать виртуально

class MyBase : virtual LibBase {};
class MyDerived: virtual MyBase, virtual LibDerived {};

Поскольку MyDerived будет иметь vtable, а MyBase будет иметь vtable, будет ли только один LibBase объект?

Надеюсь, этот вопрос достаточно ясен.

Ответы [ 2 ]

2 голосов
/ 07 августа 2009

Чтобы упростить ответ, давайте подумаем о виртуальном / не виртуальном как дублированном или недублированном контенте.

class LibDerived : LibBase

объявляет: я разрешаю, чтобы LibBase дважды (или более) входил в нисходящий из LibDerived

class MyBase : virtual LibBase {};

объявляет: я разрешаю компилятору оптимизировать две записи LibBase в нисходящих MyBase в одну.

Когда эти два объявления встречаются с каждым, первое является более приоритетным, поэтому MyDerived получает 2 имплементации LibBase. Но сила c ++ - это возможность решить эту проблему! Просто переопределите виртуальные функции MyDerived, чтобы выбрать те, которые вы хотите использовать. Другой способ - создать универсальную оболочку MyDerived, производную от интерфейса LibBase, которая объединяет любой экземпляр: LibDerived, MyBase, ... и вызывает ожидаемый метод из агрегата.

2 голосов
/ 07 августа 2009

По сути, вы правы. Вам нужно, чтобы LibDerived был получен практически из LibBase, если вы хотите, чтобы этот тип дерева наследования работал.

Если у вас этого нет, вы не можете предотвратить наличие не виртуального LibBase в LibDerived и отдельного виртуального LibBase в MyBase.

...