Существует несколько проблем для пересылки декларации:
- Это похоже на хранение имени вашего класса в нескольких местах - если вы измените его в одном месте, теперь вам придется менять его везде. Рефакторинг становится проблемой, так как код все равно будет хорошо скомпилирован с измененным именем класса, но связывание не удастся, так как предварительные объявления ссылаются на неопределенный класс. Если вы включите заголовочный файл и не будете использовать предварительные объявления, вы обнаружите эти проблемы во время компиляции.
Сложные заявления трудно поддерживать другим. Например, если заголовочный файл содержит:
include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"
вместо предварительной декларации
class Foo ;
другим легко найти, где объявлен класс Foo. С предварительным заявлением, это не так
очевидно; некоторые IDE, такие как Eclipse, могут открывать предварительное объявление, когда пользователь пытается открыть
объявление переменной.
- При связывании может произойти сбой с неопределенными символьными ошибками, когда вы включаете в код файл заголовка, который содержит прямое объявление, но фактическое определение кода находится в какой-то другой библиотеке, с которой вы не связались. Эту проблему удобнее обнаруживать во время компиляции с ошибками типа
"Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"
, так как тогда вы будете знать, где искать соответствующий Foo.cpp
и определять библиотеку, в которой он содержится.
Если вы считаете, что ваша сборка занимает слишком много времени, попробуйте выполнить компиляцию только без ссылки. Если для компиляции вашего кода требуется 10 секунд, а для компоновки - 10 минут, проблема не имеет ничего общего с несколькими дополнительными включениями. Точно так же, если ваш заголовочный файл содержит так много материала, что он действительно вызывает проблемы с производительностью, то, вероятно, пришло время реорганизовать содержимое этого файла в несколько меньших заголовочных файлов.
Так, когда это нормально для пересылки объявить? Если вы делаете это в том же заголовочном файле, что и настоящая декларация.
Пример: * * тысяча двадцать-пять
class Foo ;
typedef Foo* FooPtr ;
typedef Foo& FooRef ;
class Foo
{
public:
Foo( ) ;
~Foo( ) ;
}
OR
class TreeNode ;
class Tree
{
private:
TreeNode m_root ;
}
class TreeNode
{
void* m_data ;
} ;