Подтвердить что ты не робот

Как я могу избежать алмаза смерти при использовании множественного наследования?

http://en.wikipedia.org/wiki/Diamond_problem

Я знаю, что это значит, но какие шаги я могу предпринять, чтобы избежать этого?

4b9b3361

Ответ 1

Практический пример:

class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};

Обратите внимание, как класс D наследуется как от B, так и от C. Но оба B и C наследуют от A. Это приведет к тому, что в vtable будут включены 2 копии класса A.

Чтобы решить эту проблему, нам нужно виртуальное наследование. Это класс А, который должен быть фактически унаследован. Таким образом, это устранит проблему:

class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};

Ответ 2

виртуальное наследование. Это то, что там есть.

Ответ 3

Я бы придерживался только множественного наследования интерфейсов. Хотя множественное наследование классов иногда привлекательно, оно также может быть запутанным и болезненным, если вы регулярно полагаетесь на него.

Ответ 4

Наследование - сильное, сильное оружие. Используйте его только тогда, когда вам это действительно нужно. Раньше наследование бриллиантов было признаком того, что я собирался далеко ходить по классификации, заявив, что пользователь является "сотрудником", но они также являются "слушателем виджета", но также...

В этих случаях легко ударить несколько проблем наследования.

Я решил их, используя композицию и указатели обратно владельцу:

До:

class Employee : public WidgetListener, public LectureAttendee
{
public:
     Employee(int x, int y)
         WidgetListener(x), LectureAttendee(y)
     {}
};

После:

class Employee
{
public:
     Employee(int x, int y)
         : listener(this, x), attendee(this, y)
     {}

     WidgetListener listener;
     LectureAttendee attendee;
};

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

Ответ 6

class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {};

В этом атрибуты класса A повторяются дважды в классе D, что увеличивает использование памяти... Поэтому для сохранения памяти мы создаем виртуальный атрибут для всех унаследованных атрибутов класса A, которые хранятся в Vtable.

Ответ 7

Хорошо, великая вещь о Страшном Британии - это то, что это ошибка, когда это происходит. Лучший способ избежать - заранее выяснить структуру наследования. Например, в одном проекте, в котором я работаю, есть зрители и редакторы. Редакторы - это логические подклассы Viewers, но поскольку все зрители являются подклассами - TextViewer, ImageViewer и т.д., Редактор не выводит из Viewer, что позволяет конечным классам TextEditor, ImageEditor избегать алмаза.

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

Кроме того, вы всегда можете использовать алмаз, если вы четко указываете, какую базу вы хотите использовать. Иногда это единственный способ.

Ответ 8

Я бы предложил лучший дизайн класса. Я уверен, что есть некоторые проблемы, которые лучше всего решаются с помощью множественного наследования, но проверьте, есть ли другой способ.

Если нет, используйте виртуальные функции/интерфейсы.

Ответ 9

Использовать наследование путем делегирования. Затем оба класса будут указывать на базу A, но должны реализовать методы, которые перенаправляют на A. Он имеет побочный эффект превращения защищенных членов A в "private" членов в B, C и D, но теперь вы не нужен виртуальный, и у вас нет бриллианта.