C++ Должен ли я использовать предварительное объявление?

Я нашел этот вопрос Когда использовать предварительное объявление?, который полезен, но описателен. не предписывающий.

Мой сценарий обычно заключается в том, что я использую указатель на другой класс либо в качестве члена класса, либо в качестве аргумента функции, поэтому все, что мне нужно в заголовке, — это предварительное объявление (также в стороне, если бы я переключился на использование boost shared_ptr, они были бы совместим с использованием предварительных объявлений?). В настоящее время я просто включаю заголовки, но теперь мне интересно, следует ли мне использовать предварительные объявления.

Итак, мой вопрос: если я могу использовать предварительное объявление для класса, следует? Я надеюсь, что этот вопрос не является субъективным, но если нет ответа на лучший практический ответ, то каковы плюсы и минусы использования предварительных объявлений?

ОБНОВЛЕНИЕ

Просто чтобы расширить проблему с shared_ptr (сейчас я их не использую, но подумываю о переключении). Если бы я их использовал, я бы использовал практику определения типа shared_ptr внутри класса. Например.:

class Customer
{
public:
    typedef std::tr1::shared_ptr<Customer> SharedPointer;

    Customer() {}   
    virtual ~Customer() {}

    virtual std::string GetName() const;
};

Кажется, это может сделать вещи более грязными. Будет ли это проблематично с предварительным объявлением, и если да, то есть ли простой обходной путь?


person User    schedule 27.10.2011    source источник


Ответы (4)


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

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

Так что мой (субъективный) ответ будет Да, вы должны.

person littleadv    schedule 27.10.2011
comment
просто чтобы завершить ответ: да, boost::shared_ptr отлично работает с предварительным объявлением - person Andriy Tylychko; 28.10.2011
comment
Это быстрее и позволяет избежать проблем. Да, определенно предпочитайте предварительные объявления включению. - person Mooing Duck; 28.10.2011

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

person Ed S.    schedule 27.10.2011

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

person shashank.M    schedule 27.10.2011

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

namespace foo
{
    namespace bar
    {
        template <typename T1, typename T2, int X>
        class MyNiftyType;
        // Hmm, maybe declare more types here?
    }
    // Hmm, maybe declare even more types here?
}

Если бы всего этого можно было избежать, выполнив только #include "MyNiftyStuff.h", я бы лучше #include!

Кстати, есть стандартный заголовочный файл <iosfwd>, который содержит предварительные объявления для некоторых типов потоков. Кажется, это специально придумано, чтобы вы могли объявить operator<<(std::ostream&, ...) (это мое личное мнение, извините, если все-таки не так).


Редактировать: относительно shared_ptr<type>.

Грубо говоря, единственное, что вы можете делать с общими указателями (на предварительно объявленные типы), — это объявлять функции. Если вы хотите определить функцию, которая делает что-то полезное с shared_ptr<type>, вы не можете просто предварительно объявить type. Например:

МойКод.h

class MyClass;
void DoMuchStuff(shared_ptr<MyClass> ptr); // declaration - OK
inline void DoDoubleStuff(shared_ptr<MyClass> ptr) // definition - not OK!
{
    void DoMuchStuff(ptr);
    void DoMuchStuff(ptr);
}

Если бы я использовал обычный указатель вместо shared_ptr, это работало бы с предварительными объявлениями. Но это неудобство редко касается вас — либо у вас есть только объявления в ваших .h файлах, либо ваши встроенные функции настолько сложны, что вам все равно придется #include полностью объявлять свой класс.

person anatolyg    schedule 27.10.2011
comment
Правильно, пока вы не #include что-то, что вызывает проблемы при включении в другой файл. Кого волнует, длинное ли имя типа, если компромиссом является более быстрая компиляция и менее подверженная ошибкам структура кода? - person Ed S.; 28.10.2011