C ++, алмазное наследование, где / когда нужно внедрять чистые виртуалы? - PullRequest
2 голосов
/ 16 сентября 2011

C ++: у меня есть базовый класс A с чисто виртуальной функцией f (), а затем два класса B и C наследуются практически от A, и класс D, который наследуется от B и C (типичная структура ромба): 1001 *

   A f() = 0
 v/ \v
 B   C
  \ /
   D

Где и когда необходимо реализовать f () = 0 в следующих случаях?

  1. И B, и C имеют также чисто виртуальные функции (-> делают ли абстрактные классы должны реализовать унаследованные чистые виртуалы?)
  2. Только один из них (B XOR C) имеет чисто виртуальную функцию (-> другой все еще должен реализовать f ()?)
  3. Ни B, ни C не имеют своих собственных чистых виртуалов (-> возможный способ пропустить реализацию в B и C и "передать ее" D?)
  4. В каком из трех приведенных выше случаев D нужно реализовать f ()? В каких случаях для D возможно реализовать функцию f ()? В каких случаях, если таковые имеются, не возможно ли для D реализовать f ()?

Существуют ли другие распространенные предложения для подобных проблем?

Спасибо.

Ответы [ 4 ]

1 голос
/ 16 сентября 2011

И B, и C имеют также чисто виртуальные функции (-> должны ли абстрактные классы реализовывать унаследованные чистые виртуалы?)

Да D НЕОБХОДИМО реализовать ВСЕ унаследованные чистые виртуальные функции.
Если класс не реализует все чистые виртуальные функции классов, он наследуется от самого класса, действующего как абстрактный класс.

Только один из них (B XOR C) имеет чисто виртуальную функцию (-> должен ли другой по-прежнему реализовывать f ()?)

D потребуется для реализации чистоговиртуальная функция, которую он наследует через свои базовые классы в любой иерархии.Если его непосредственный базовый класс не определяет виртуальную функцию Pure, то этот класс тоже становится абстрактным классом, и, если D не реализует унаследованную чистую виртуальную функцию, он тоже станет абстрактным.

Ни B, ни C не имеют своих собственных чистых виртуалов (-> возможный способ пропустить имплментацию в B и C и "пропустить ее" к D?)

D должен будет реализовать чисто виртуальные функции, которые он наследует через A->B & A-C. Обратите внимание, что в этом случае и B, и C будут абстрактными классами.

В каком из трех вышеупомянутых случаев D должен реализовать f ()?В каких случаях это возможно для D, чтобы реализовать f ()?В каких случаях, если таковые имеются, не возможно ли для D реализовать f ()?

D должен реализовать foo() во всех 3 вышеупомянутых условиях, чтобы иметь возможность быть инстанцируемым(Non-Abstract).

Вывод:

  1. Класс должен реализовывать ВСЕ чистые виртуальные функции, которые он наследует от ВСЕХ своих базовых классов, не в состоянии сделатьпоэтому сделаем класс абстрактным классом.
  2. Виртуальный атрибут наследуется. Если суперкласс объявляет функцию виртуальную, то переопределенная функция в производном классе также является виртуальной и передает виртуальный атрибут всем классам, производным от него.

Избегайте Алмаза Смерти !Если вы действительно не понимаете тонкости, связанные с этим.Многие люди пытаются использовать виртуальное наследование, когда это не самый удачный способ достичь того, чего хочет добиться их дизайн.Использование виртуального наследования действительно необходимо в некоторых сценариях, тем не менее, это важная конструкция, предоставляемая языком, но чаще используемая неверным образом.Поэтому имеет смысл один раз пересмотреть свой дизайн, чтобы проверить, действительно ли вам нужно виртуальное наследование.

Следующее может быть хорошим чтением:

  1. Множественное наследование - Часть I
  2. Множественное наследование - Часть II
  3. Множественное наследование - Часть III
0 голосов
/ 16 сентября 2011
  1. Нет, абстрактные классы (предположительно B и C) не должны реализовывать унаследованные чистые виртуальные объекты. Дочерний класс, такой как D, должен быть создан для создания экземпляра.

  2. Нет, снова B и C унаследуют чисто виртуальный метод, и его нужно только переопределить для создания окончательного конкретного класса.

  3. Да, это будет проходить через реализацию к D одним из двух способов. Если B и C оба наследуют виртуально, то D осуществит это один раз. Если они не наследуют виртуально, тогда D необходимо будет переопределить и B и C версий f, чтобы они были конкретными.

  4. Если D является абстрактным, ему не нужно реализовывать f. Предполагая, что вы имеете в виду конкретность, во всех трех случаях вам нужно переопределить f в D. Только если B и C переопределить f, D не потребуется.

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

0 голосов
/ 16 сентября 2011

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

Таким образом, D должен реализовать все, что еще не было реализовано, или все было реализовано более одного раза по разным путям (для устранения неоднозначности). Если что-то - на уровне D - все еще не реализовано ... D не может быть установлено, и реализация требуется для E, полученного из D.

- Бриллианты вечны -

0 голосов
/ 16 сентября 2011

И B, и C имеют также чисто виртуальные функции (-> а абстрактные классы должны реализовывать унаследованные чистые виртуалы?

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

Только один из них (B XOR C) имеет чисто виртуальную функцию (-> должен ли другой по-прежнему реализовывать f ()?)

Поскольку C также является производным от A, он также должен реализовывать f().

Ни B, ни C не имеют своих собственных чистых виртуалов (-> возможный способ пропустить имплантацию в B и C и "пропустить это" к D?)

Вы можете сделать это. Но это предотвращает создание экземпляров B или C в одиночку, как -

A *obj = new B(); // Error
A *obj = new C(); // Error

В каком из трех приведенных выше случаев D нужно реализовать f ()? В каких случаях это возможно для D, чтобы реализовать f ()? В каких случаях, если таковые имеются, не возможно ли для D реализовать f ()?

f() может быть реализовано только в D, если вы хотите, чтобы все его родительские классы были абстрактными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...