Отдельные заголовочные файлы для конкретных классов - C ++ - PullRequest
5 голосов
/ 18 февраля 2009

Фон

У меня есть абстрактный класс, что-то вроде

class IConverter{
    public:
    virtual void DoConvertion() = 0;
};

Будет много конкретных классов, которые просто реализуют DoConvertion метод.

class TextConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

class ImageConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

Будет много конкретных реализаций, подобных этой. Я создал заголовочный файл, скажем, CharacterConverter.h , который имеет абстрактный класс IConverter .

Вопрос

Поскольку мои конкретные классы просто реализуют метод DoConvertion , требуется ли создавать отдельные заголовочные файлы для каждого конкретного класса? Я имею в виду, нужно ли создавать ImageConverter.h , TextConverter.h и так далее для всех конкретных классов? Все эти заголовочные файлы будут содержать один и тот же код, как IConverter абстрактный класс.

Есть мысли?

Ответы [ 7 ]

8 голосов
/ 18 февраля 2009

Не требуется. Это в основном решение суда.

Если реализация проста для каждого класса, вы можете поместить их все в один .h и один .cpp

Если реализации немного длиннее, то лучше использовать отдельный файл .h и .cpp для каждого.

Некоторые преимущества использования разных .h / .cpp для каждого класса:

  • Он сохранит код в чистоте и порядке
  • Сокращенная работа по компиляции: изменение в одной из реализаций не должно будет перекомпилировать все остальные
  • Ускорение времени компиляции: несколько компиляторов могут компилировать несколько файлов одновременно, например, переключатель Visual Studio / MP. С несколькими файлами у вас будет меньше времени на компиляцию.
  • Другие файлы могут включать в себя только то, что им нужно, а не все
  • Более быстрое время соединения: время соединения будет сокращено из-за добавочного соединения
  • Используя управление версиями, вы можете оглянуться назад только на изменения в конкретном производном классе, вместо того чтобы просматривать все изменения, сделанные в массивном файле 1 .h / .cpp, чтобы найти это одно изменение в конкретном производном классе.
1 голос
/ 18 февраля 2009

Вам, вероятно, будет лучше использовать фабрики или указатели функций.

Однако, один особенно неприятный способ, который приходит на ум, это использовать макрос для объявления ваших конкретных классов. Например:

В нижней части IConverter.h есть следующий макрос

#define DECLARE_CONVERTER_CLASS(CLASS_NAME) \
class CLASS_NAME : public IConverter\
{ \
    public: \
    CLASS_NAME() {} \
    virtual void DoConversion(); \
}; \

Тогда в MyConverter1.cpp

DECLARE_CONVERTER_CLASS(MyConverter1)

virtual void MyConverter1::DoConversion()
{
    ...
}

Фу: -)

1 голос
/ 18 февраля 2009

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

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

1 голос
/ 18 февраля 2009

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

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

На основании комментариев я бы порекомендовал такую ​​структуру:

IConverter.h ==> определение IConverter
Converters.h ==> определения всех подклассов
IConverter.cpp ==> включает IConverter.h и Converters.h, содержит реализацию абстрактной функциональности IConverter (статический метод фабрики и любую наследуемую функциональность)
TextConvter.cpp, ImagerConverter.cpp и т. Д. ==> отдельные файлы cpp для каждого подкласса, каждый из которых содержит IConverter.h и Converters.h

Это позволяет включать IConverter.h только в любые клиенты, которые используют заводские и общие функциональные возможности. Поместив все другие определения в один заголовок, вы сможете объединить, если они в основном одинаковы. Отдельные файлы cpp позволяют вам воспользоваться преимуществами компилятора, упомянутыми Брайаном. Вы могли бы включить определения подкласса в заголовочных файлах, как уже упоминалось, но это на самом деле ничего вам не дает. Ваш компилятор, как правило, умнее, чем вы, когда речь идет об оптимизации, например, встроенной.

1 голос
/ 18 февраля 2009

Лучший ответ на это - то, что легче читать. Вам и другим программистам будет сложно найти один длинный исходный файл. С другой стороны, многие крошечные (наполовину полноэкранные) исходные файлы так же плохи.

1 голос
/ 18 февраля 2009

Вам понадобятся определения конкретных классов для создания объектов, поэтому вам нужно будет поместить эти определения в файл .h. В какой файл вы их положите, решать только вам.

1 голос
/ 18 февраля 2009

Вы, вероятно, получите ответы в обоих направлениях.

Я бы сказал, что для любых тривиальных преобразователей достаточно иметь их всех в одной паре .h / .cpp и разбивать каждого на одну пару излишне Я думаю, что компромисс между обслуживанием большого количества файлов и обслуживанием множества методов в одном файле в этом случае стоит.

Сложные преобразования, вероятно, заслуживают собственных пар файлов.

...