Класс с сочетанием чистых виртуальных и виртуальных методов

Я создал абстрактный класс, в котором есть только набор чистых виртуальных методов. Есть 3 разных класса, которые имеют конкретные реализации этих методов.

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

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


person TheWaterProgrammer    schedule 10.01.2017    source источник
comment
Как вы думаете, почему базовые классы могут иметь только чисто виртуальные методы?   -  person Algirdas Preidžius    schedule 10.01.2017
comment
Да, это нормально. Это по-прежнему абстрактный базовый класс, если он содержит один или несколько чистых виртуальных классов, поскольку вы не можете создать его экземпляры, но перемещение общих функций в него - это хорошо.   -  person Colin    schedule 10.01.2017
comment
Если вы действительно хотите сохранить свой корневой интерфейс полностью чистым (например, полностью скрыть реализацию в динамической фабричной библиотеке), вы также можете просто реализовать промежуточный BaseImpl, который наследуется от вашего чисто-виртуального интерфейса, реализует общий код, подтверждает оставшиеся чистые виртуальные , и ваши конкретные финалы могут унаследовать от that.   -  person WhozCraig    schedule 10.01.2017
comment
@ AlgirdasPreidžius, как я уже сказал, он компилируется и работает. Мой вопрос связан с принципами дизайна. в основном это хороший подход к дизайну?   -  person TheWaterProgrammer    schedule 10.01.2017
comment
@SegmentationFault И мой вопрос был связан с тем же. Разрешите уточнить: как вы думаете, почему это плохой дизайн?   -  person Algirdas Preidžius    schedule 10.01.2017
comment
@ AlgirdasPreidžius Я не думал, что это плохо. но я не был уверен, хороший это дизайн или плохой. вот и захотелось подтвердить это со специалистами. пожалуйста, поделитесь своими мыслями, если они у вас есть (adv / dis-adv)   -  person TheWaterProgrammer    schedule 10.01.2017
comment
@SegmentationFault Ну, лично я не вижу недостатков, так как любой шаблон, исключающий копирование кода, лучше. Копирование кода, как правило, следует избегать, и это является запахом плохого дизайна. И поэтому своего ответа я не написал, так как он был бы слишком коротким, на мой вкус :)   -  person Algirdas Preidžius    schedule 10.01.2017
comment
@ AlgirdasPreidžius согласен с вашей точкой зрения   -  person TheWaterProgrammer    schedule 10.01.2017


Ответы (3)


Это абсолютно нормально, хотя, похоже, появился шаблон, в котором вы поместили бы все и только свои чистые виртуальные функции в класс, который будет рассматриваться как более интерфейс.

Затем вы должны определить класс, который реализует «общие» части этого интерфейса, и унаследовать 3 класса от этого класса.

Со временем кажется, что это поддается более масштабируемому и простому в поддержке коду.

Java, ради интереса, в значительной степени заставляет использовать этот шаблон.

person Bathsheba    schedule 10.01.2017

Очевидно, это зависит от отношений между классами. Другими словами, это выбор дизайна или реализации (то есть зависит от вас, если вы можете разумно его обосновать). Технически ничто не мешает классу иметь сочетание виртуальных, чисто виртуальных, невиртуальных и статических функций-членов.

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

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

В качестве грубого примера того, что вы предлагаете, не имеет смысла, рассмотрим это

  class Aircraft
  {
       public:
            virtual void Manoeuvre() = 0;
  };

  class Hornet : public Aircraft   //  F/A-18 hornet fighter aircraft
  {
        public:

              void Manoeuvre();
  };

  class Tomcat : public Aircraft    //  F-14 tomcat fighter aircraft
  {
        public:

               void Manoeuvre();
  };

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

  class Hercules : public Aircraft    //  C-130 hercules cargo plan
  {
        public:

               void Manoeuvre();
  };

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

В этом случае я мог бы рассмотреть возможность введения промежуточных классов, таких как Fighter (который мог бы быть общей базой для Hornet и Tomcat, но не Hercules) и - если я хотел бы представить несколько типов грузовых самолетов - возможно, CargoPlane будет общим база для тех. Тогда и Fighter, и CargoPlane могут быть производными от Aircraft, но Aircraft не обеспечивает функциональность, которая имеет смысл только для некоторых типов самолетов.

Случайный комментарий: хотя некоторые люди утверждают обратное, в C ++ нет ничего, что мешало бы чистой виртуальной функции иметь определение (реализацию). Это означает, что функция ДОЛЖНА быть переопределена производными классами, но существует определение по умолчанию (которое может быть явно вызвано функциями в производных классах), предоставляемое базовым классом.

person Peter    schedule 10.01.2017

Да это хорошо. Однако: если это все классы, которые у вас есть, нет необходимости делать реализации базового класса virtual.

person Petter Hesselberg    schedule 10.01.2017
comment
ITYM, если это все производные классы, которые у вас когда-либо будут. ;-) - person Cheers and hth. - Alf; 10.01.2017
comment
И да и нет. Если эти классы являются частью общедоступного API или могут потребовать обратной двоичной совместимости, проектируйте с учетом будущего (virtual). В противном случае вы можете сделать методы виртуальными позже, если требования изменятся ... - person Petter Hesselberg; 10.01.2017