2017-01-25 9 views
1

Я учу C++, и мне нужен хороший, простой, повседневный пример, если вы будете использовать это:Мне нужен простой пример, когда использовать невиртуальном множественное наследование

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

Здесь D наследует два раза потому что виртуального наследования нет.

Мне нужен простой для понимания мотивационный пример того, когда вам может понадобиться эта конструкция. Мне даже не нужен код для этого; Мне просто нужно представить пример своим ученикам, чтобы они воскликнули: «Да, я вижу, что это было бы полезно!»

+0

Почему вы могли бы убедить их, что это может быть полезно? ИМХО, это совсем не важно. Они почти никогда не видят этого на ЗЕМЛЕ. Даже пример Королевы не так правилен. – AhmadWabbi

+3

«Королева наследует от епископа и ладьи», это не является хорошим примером отношения * is-a *. –

+0

Я согласен с @AhmadWabbi, что это редкая конструкция; но студенты спросят, почему C++ поддерживает как виртуальное, так и не виртуальное наследование. – oz1cz

ответ

1

Я предлагаю этот пример для виртуального и невиртуального множественного наследования:

А -> Человека (идентификатор, имя)

B -> Учитель (зарплата)

C - -> Student (знаки)

D -> AssitantTeacher

Для меня AssistantTeacher это свеже-закончил учитель, который преподает и готовит более высокую степень (Магистров или кандидатов наук). У него есть зарплата, а также отметки.

Чтобы добавить не виртуальный вкус, предположим, что учителя имеют идентификаторы в определенном формате, а учащиеся имеют идентификаторы в другом формате. У AssistantTeacher есть два идентификатора: один идентификатор учителя (который используется в качестве первичного ключа в базе данных HR) и один идентификатор студента (который используется как ПК в базе данных академической системы).

[EDIT]

В качестве примера, система HR ERP даст автоинкрементный идентификатор для учителей, а академическая система студентов даст студентам идентификаторы формата: YYYYMMSAAAA (где Y является годом зачисление ученика, M - месяц, S - пол: 0 или 1, а A - часть с автоинкрементами).

ПомощникТехник может иметь идентификатор «1332» в системе HR и «20170100004» в качестве идентификатора студента.

+0

Если 'id' является конкретным, он должен, вероятно, перейти в' Учитель'/'Студент'. – Jarod42

+0

@ Jarod42 Каждый человек имеет идентификатор, но формат является конкретным и отличается в двух классах. У AssistantTeacher есть два разных идентификатора одновременно – AhmadWabbi

+0

Учитель может быть Студентом, и наоборот. – Peter

2

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


Longer версия: Ситуация вы описываете здесь известен как the diamond problem. Это именно та ситуация, которую виртуальное наследование стремится решить.

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

  • множественное наследование (MI) существует в C++ и полезно для объединения нескольких интерфейсов в одном
  • Virtual MI существует в C++ и полезен для решения проблемы алмазной
  • Не виртуальный MI в алмазной конфигурации существует только как побочный эффект MI и нежелателен.

Что касается виртуального MI Я хотел бы использовать пример разделения интерфейс- и реализацией иерархий (или расширение интерфейсов). Например, когда у вас есть такие конфигурации: enter image description here

+0

Я не верю, что фразы типа «алмаз смерти смерти» полезны. – curiousguy

+0

@curiousguy вы могли бы уточнить? Это другое название проблемы с алмазом, которая фактически используется (даже упоминается в статье wiki). Что с этим не так? – AMA

+0

Это глупое имя. Он призван спровоцировать иррациональный страх и создать впечатление, что МИ создает очень сложные проблемы. – curiousguy

1

Это непростой вопрос, потому что любое обсуждение этого вопроса приведет к наследованию и композиции.

Для примера виртуального наследования, я буду держать свой шахматный пример

     Chess_piece 
         attributes: pos_x, pos_y; 
        /\ 
    _________________/ \___________________ 
/          \ 
Bishop          Rook 
methods:         methods:  
    first_diagonal_move(length)     horizontal_move(length) 
    second_diagonal_move(length)    vertical_move(length) 
    \__________________  ___________________/ 
        \ /
        Queen 

И Королева наследует от методов как ладьи и слона, но королева имеет атрибуты только одного куска, так здесь мы будем использовать виртуальное наследование C++.

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

Point        Point 
attributes: pos_x, posy   attributes: pos_x 
    |         | 
    |         | 
Circle        | 
attribute: radius     | 
    \___________  ________________/ 
       \ /
       Figure 

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

На самом деле это происходит потому, что во втором случае мы пытаемся использовать наследование, где правильный шаблон должен быть составным: фигура фактически содержит точку и круг. Этот вид не виртуального наследования приводит к сложным вопросам, таким как . Какова позиция фигуры?. По этой причине OO советует использовать правило composition over inheritance.

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

TL/DR: множественное наследование по сам по себе является сложным шаблоном, который не допускается по этой причине на некоторых пост-языках C++, таких как Java. Не виртуальное множественное наследование, как правило, представляет собой намек на паттерн запаха, поскольку наследование использовалось там, где должна быть композиция. Но если вы знаете, почему вы его используете (избегая дублирования кода является приемлемой причиной), и вы его документируете, его можно использовать. В конце концов, это разрешено языком C++ ...

0

В C++ наследование не всегда означает подтипирование, по крайней мере доступный подтипирование: отношение наследования имеет контроль доступа, как и доступ к члену.

Не виртуальное наследование является исключительным отношением наследования. Виртуальное наследование - это отношение наследования, которое может быть разделено.

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

Inheritance позволяет производному классу переопределять виртуальные функции. Поскольку виртуальное наследование является общим отношением, ответственность за переопределение виртуальной функции базового класса разделяется между несколькими классами «родной»; эти братья и сестры должны сотрудничать в том, как они переопределяют (общие) виртуальные функции базового класса (общего).

Вы должны использовать не виртуальное наследование, когда:

  • инициализация должна производиться непосредственно немедленным подкласса, с определенными параметрами
  • наиважнейшая классом «родственный» было бы неуместно