Вы не должны их использовать, но у них есть свои преимущества.
Обычно они используются в качестве «интерфейса» между двумя различными типами функциональности, которые, с точки зрения кода, не очень связаны.
Примером может служить загрузка файла. Простой класс обработки файлов может показаться идеальным. Однако на более позднем этапе вас попросят перенести все ваши файлы в один упакованный файл, сохраняя при этом поддержку отдельных файлов в целях отладки. Как вы справляетесь с загрузкой здесь? Очевидно, что все будет работать по-другому, потому что вдруг вы не можете просто открыть файл. Вместо этого вам нужно иметь возможность искать местоположение файлов, а затем искать его перед загрузкой, почти как обычно.
Очевидная вещь, которую нужно сделать, - реализовать абстрактный базовый класс. Возможно, назовите это 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.