2015-03-17 1 views
2

В документе JSF C++ Coding Standards, AV Правило 87 показывает диаграмму абстрактного базового класса и реализацию как множественного наследования.C++ Многократное наследование для осуществления полиморфизма

  1. Что это за диаграмма пытается показать?

  2. В этом примере, Какова цель наследования Private/Protect?

  3. Каким образом создается реализация в качестве базового класса?

  4. Схема из правила AV 87 показывает, что D1 наследуется от имплантата; Является ли это другой реализацией, которая не имеет никакого отношения к интерфейсу?

А.В. Правило 87

Иерархии должна быть основана на абстрактных классов. См. Stroustrup 2, 12.5.

Обоснование: иерархий на основе абстрактных классов, как правило, сосредоточены конструкции в сторону производства чистых интерфейсов, сохранить детали реализации выхода из интерфейсов, а также свести к минимуму зависимости компиляции, позволяя альтернативные реализации сосуществовать. См. Правило AV 87 в Приложении A . Предпочтительны AV Правило 87

иерархий на основе абстрактных классов -

...

Приложение A. Поэтому иерархии в верхней части диаграммы предпочтительнее иерархии в нижней части диаграммы. JSF AV Rule 87

Используя классический пример полиморфизма форм:

Classic Shapes Polymorphism example

5. бы быть моя реализация следующих? Мне это не кажется правильным. Боюсь, мне не хватает цели дизайна. Традиционно я ожидал бы, что Right_Triangle наследуется от Triangle.

class Shape{};        // Interface 
class Right_Triangle{};      // Impl  
class Triangle : public Shape, 
        private Right_Triangle {}; // D1 

ответ

2

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

class IShape { ... };  
class TriangleImpl { ... }; 
class Triangle : public IShape, 
       private TriangleImpl { ... }; 

Диаграмма, которая подразумевает, что право треугольник является треугольником неправильным и распространенным заблуждением. Правильный треугольник не является треугольником, если вы явно не ограничиваете, что вы можете сделать с треугольником (например, сделать его только для чтения). Треугольник может иметь любые длины ребер, которые вы желаете. Класс, наследующий от треугольника, должен все равно действовать как треугольник. Он известен как Liskov Substitution Principle.

Поскольку вы не можете использовать RightTriangle класс везде Triangle класс можно использовать без ограничений, которые делают Triangle бесполезным в качестве конкретного класса (вы не можете установить длины ребер на треугольнике) - таким образом, иерархию наследования как показанный просто плохая конструкция.

Конструкция иерархии классов не обязательно следует диаграмме Венна и не должна следовать «обычным истинам». Длительная практика разработки программного обеспечения показывает, что правильные диаграммы наследования получаются при использовании LSP.

Да, учебники, демонстрирующие этот «правильный треугольник - треугольник», безумие являются неправильными, если они не предлагают конкретный дизайн, который удовлетворяет LSP. В случае с формами интерфейсы Trilateral и Quadrilateral должны быть прочитаны только, а конкретные методы установки вершин или границ могут быть предложены только в производных классах, поскольку они соответствуют различным ограничениям. Полученные конкретные классы нуждаются в плоской иерархии (Square - это не Rectangle - если бы это было так, вы могли бы установить для него две разные длины!). Аналогично, что касается LSP, то Square не является Quadrilateral, так как quadrilaterals могут иметь произвольно расположенные вершины и т. Д.

+0

Я не уверен, что понимаю «дух» AV 87. Я до сих пор не понимаю преимуществ (или минусов) наследования от вашей реализации. Не могли бы вы подробнее остановиться? – Jerunh

+1

@ Jerunh Класс реализации вынужден, по своему усмотрению, выполнять только одну вещь или один аспект работы, аспект должен быть самодостаточным по дизайну. Класс 'Triangle' содержал бы, вероятно, некоторые тривиальные адаптеры между' IShape' и 'TriangleImpl'. Это упрощает замену реализаций. –

+1

@KubaOber: хотя в ответе я использовал оператор «Правый треугольник - треугольник», я согласен с вашим ответом. Возможно, это крушение ОО в том, что объекты, представляющие реальность, действительно сложны. Контекст (проблемный домен) здесь ключевой: если объекты представляют собой рисунки, то утверждение «Правый треугольник - это треугольник» может быть истинным (хотя и бесполезным, правый треугольник должен быть экземпляром), но для геометрических объектов вы правы. Кстати: иерархии животных еще хуже. – stefaanv

2

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

В вашем примере Shape должен быть абстрактным классом в соответствии с правилом кодирования. Таким образом, форма может объявлять только чистые виртуальные функции, такие как Print(), Load(), rotate(), ...

Чтобы наследовать другую реализацию (рядом с иерархией фигур), нельзя использовать общедоступное наследование.

+0

Не могли бы вы объяснить, что вы намереваетесь унаследовать от другой реализации? Каков был бы пример этого? – Jerunh

+1

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