Недостатки предварительной декларации? - PullRequest
10 голосов
/ 02 ноября 2011

В C ++ и Objective-C у меня появилась привычка заранее объявлять любые необходимые классы, которые не нужно определять в заголовке, а затем импортировать заголовочные файлы, определяющие эти классы в исходных файлах, если это необходимо.

Была ли когда-нибудь ситуация, в которой это не было бы хорошей идеей?

(Я знаю, что большим недостатком прямого объявления является ограниченное удобство использования неполного типа. Для целей этого вопроса предположим, что в заголовке мне нужно использовать только объявленный заранее класс как неполный тип.)

Ответы [ 7 ]

7 голосов
/ 02 ноября 2011

Иногда вы можете слегка изменить семантику программы, не вызывая ошибок

class Foo;

template < typename T>
struct Trait
{
    static const int MY_TYPE = -1;
};

// Lets say this is Foo.h
//class Foo
//{
//};
//template<>
//struct  Trait<Foo>
//{
//  static const int MY_TYPE = 1;
//};

void TestFunction(Foo& f)
{
    std::cout << Trait<Foo>::MY_TYPE << std::endl;
}

Рассмотрим приведенный выше код, а закомментированный код находится в заголовке. Если заголовок включен, TestFunction выведет 1, иначе -1

3 голосов
/ 02 ноября 2011

Одним из недостатков может быть отсутствие сокрытия / инкапсуляции информации.

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

EDIT:

Люк попросил привести пример, так что вот так:

Предположим, у вас есть класс с именем Car. И единственное, для чего вы его построили, - это перейти из точки А в точку Б. Лично я предпочел бы сохранить свой заголовочный файл в классе: Car и метод Drive. Исходя из того, как вы сформулировали свой вопрос («все классы, которые я могу»), я ожидаю найти такие классы, как «DieselEngine», «PetrolEngine», «HybidEngine» и тому подобное, в вашем заголовочном файле. Проблема в том, что другие люди, работающие над вашим проектом (или вы, со временем), начинают использовать эти открытые классы. Теперь, два года спустя, вы решаете: «Хм ... этот класс PetrolEngine действительно вызывает у меня проблемы. Я думаю, что я просто собираюсь удалить его и заменить его на HybridEngine полностью в моем классе автомобилей» - ну, теперь PetrolEngine включено в 100 других файлов по причинам, которые вы не понимаете - и теперь вы вынуждены держать PetrolEngine (и работать как раньше) для всех тех парней, которые использовали его в некоторых, говорят, что вы на самом деле не уверены - потому что у вас не было надежного рабочего «контракта» на то, как вы хотели, чтобы этот класс использовался в первую очередь. Это была деталь реализации того, чего вы действительно хотели достичь - построить автомобиль.

РЕДАКТИРОВАТЬ, чтобы обсудить комментарии о сокрытии информации:

Если все, что вы делаете, это строго вперед, объявляя имя класса / структуры - ну, я думаю, я бы снова спросил «почему». Если я являюсь потребителем вашего заголовочного файла и класса (классов), и я не могу ничего сделать с этим классом - и он не представлен как параметр или тип возврата API вашего основного класса - тогда зачем вообще его выставлять

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

2 голосов
/ 02 ноября 2011

Форвардные объявления могут применяться ко многим вещам: классам, функциям, глобальным переменным / константам (используя extern) и в C ++ 11, перечисления.

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

Если у вас есть ошибка с предварительным объявлением класса, глобального или перечисления, компилятор должен забрать его (да!).

Если у вас есть ошибка с объявлением функции, то в C ++ вы просто создали перегрузку (oups!).

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

0 голосов
/ 02 ноября 2011

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

0 голосов
/ 02 ноября 2011

Одним из недостатков является потенциальная утечка памяти в заранее объявленных типах.См. этот вопрос для более подробной информации.Компиляторы Microsoft выдают warning C4150: deletion of pointer to incomplete type 'SomeType'; no destructor called в этом случае.

0 голосов
/ 02 ноября 2011

Форвардные объявления предпочтительнее полного включения файла, если вам не нужно полное определение класса в заголовке.Единственный недостаток, о котором я могу думать, был уже опубликован как комментарий @Stephen Darlington, который я бы дал 10 голосов, если бы мог.:)

0 голосов
/ 02 ноября 2011

Нет, насколько я знаю. Единственный недостаток, который вы уже рассмотрели, - это использование неполных типов. Поскольку вы говорите, что не будет никаких типов использования, которым нужны полностью определенные типы, я думаю, вы в порядке.

...