Дизайн с (чистым) виртуальным C ++ - PullRequest
0 голосов
/ 29 октября 2009

Прежде всего я должен упомянуть, что я прочитал много виртуальных вопросов C ++ по stackoverflow. У меня есть некоторые знания о том, как они работают, но когда я запускаю проект и пытаюсь спроектировать что-то, я никогда не рассматриваю / не использую виртуальные или чисто виртуальные реализации. Может быть, это потому, что у меня нет знаний о том, как они работают, или я не знаю, как реализовать что-то с ними. Я думаю, что это плохо, потому что я не использую полностью объектно-ориентированную разработку.

Может быть, кто-то может посоветовать мне, как к ним привыкнуть?

Ответы [ 5 ]

1 голос
/ 31 октября 2009

Если вы загляните в Google для шаблонов дизайна, таких как «шаблон стратегии» и «шаблон команды», вы найдете несколько хороших вариантов использования интерфейсов и полиморфизма. Кроме того, шаблоны проектирования всегда очень полезно знать.

1 голос
/ 31 октября 2009

У меня нет тонны времени в банкомате, но вот простой пример.

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

Теперь в коде я использую абстрактный класс с именем «iMotor», который содержит только чисто виртуальные функции. В коде реализации упоминается только класс iMotor. Я создаю dll для разных типов двигателей с разными реализациями, но все они реализуют интерфейс iMotor. Итак, все, что мне нужно сделать, чтобы добавить / изменить двигатель, это создать новую реализацию и удалить эту dll вместо старой. Поскольку код, использующий эти реализации двигателя, имеет дело только с интерфейсом iMotor, который никогда не нужно изменять, для изменения требуется только реализация how каждого двигателя.

1 голос
/ 29 октября 2009

но когда я запускаю проект и пытаюсь спроектировать что-то, я никогда не рассматриваю / не использую виртуальные или чисто виртуальные реализации.

Вот что вы можете попробовать:

  • Определите набор классов, которые вы используете
  • Видите ли вы некоторые иерархии классов? A Circle is-a Shape род отношений?
  • Изолировать поведение
  • Поведение пузыря вверх / вниз для формирования интерфейсов (базовых классов) (Код для интерфейсов, а не реализаций)
  • Реализуйте их как virtual функции
  • Ответственность за определение точной семантики операции (й) лежит на подклассах
  • Создайте свои подклассы
  • Реализация (переопределение) виртуальных функций

Но не навязывайте иерархию только ради их использования. Пример из реального кода, над которым я недавно работал:

class Codec {
public:
   virtual GUID Guid() { return GUID_NULL; }
};

class JpegEncoder : public Codec {
public:
   virtual GUID Guid() { return GUID_JpegEncoder; }
};

class PngDecoder : public Codec {
public:
   virtual GUID Guid() { return GUID_PngDecoder; }
};
1 голос
/ 29 октября 2009

Вы не должны их использовать, но у них есть свои преимущества.

Обычно они используются в качестве «интерфейса» между двумя различными типами функциональности, которые, с точки зрения кода, не очень связаны.

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

Очевидная вещь, которую нужно сделать, - реализовать абстрактный базовый класс. Возможно, назовите это BaseFile. Обработка функции OpenFile зависит от того, используете ли вы PackageFile или класс DiskFile. Так что сделайте это чисто виртуальным.

Затем, когда вы получаете классы PackageFile и DiskFile, вы предоставляете соответствующую реализацию для открытия файла.

Затем вы можете добавить что-нибудь, например

#if !defined( DISK_FILE ) && defined ( _DEBUG )
#define DISK_FILE 1
#elif !defined( DISK_FILE )
#define DISK_FILE 0
#endif

#if DISK_FILE
typedef DiskFile File;
#else
typedef PackageFile File;
#endif

Теперь вы просто используете typedef «Файл», чтобы выполнить всю обработку файла. Точно так же, если вы предварительно не определили DISK_FILE как 0 или 1, и отладка установлена, он будет автоматически загружаться с диска, в противном случае он будет загружаться из файла пакета.

Конечно, такая конструкция по-прежнему позволяет вам загружать из файла Package в отладочном режиме, просто определяя DISK_FILE равным 1, и также позволяет использовать доступ к диску в сборке релиза, устанавливая DISK_FILE в 0.

1 голос
/ 29 октября 2009

Ознакомьтесь с абстрактными базовыми классами и интерфейсами в Java или C #, чтобы получить представление о том, когда полезны чистые виртуалы.

Виртуальные функции довольно просты для ОО. Есть много книг, чтобы помочь вам. Мне нравится, что Ларман применяет UML и шаблоны .

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