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

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

Я знаю то, что это означает, но какие шаги я могу сделать для предотвращения его?

55
задан Mateen Ulhaq 14 December 2015 в 19:23
поделиться

6 ответов

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

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

Уведомление, как класс D наследовал от обоих B & C. Но оба B & C наследовались A. Это приведет к 2 копиям класса A, включаемого в vtable.

Для решения этого нам нужно виртуальное наследование. Это - класс A, который должен быть фактически наследован. Так, это устранит проблему:

class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
67
ответ дан Mark Ingram 7 November 2019 в 07:19
поделиться

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

14
ответ дан eduffy 7 November 2019 в 07:19
поделиться

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

12
ответ дан Bob Somers 7 November 2019 в 07:19
поделиться

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

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

я решил их при помощи состава и указателей назад на владельца:

Прежде:

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
ответ дан 7 November 2019 в 07:19
поделиться

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

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

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

1
ответ дан coppro 7 November 2019 в 07:19
поделиться

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

В противном случае используют виртуальные функции/интерфейсы.

0
ответ дан user17720 7 November 2019 в 07:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: