Следует ли использовать, когда это возможно, предварительные декларации вместо включений?
Нет, явные предварительные декларации не должны рассматриваться в качестве общего руководства.Форвардные объявления, по сути, представляют собой скопированный и вставленный код или код с ошибкой, который в случае обнаружения в нем ошибки необходимо исправлять везде, где используются форвардные объявления.Это может быть подвержено ошибкам.
Чтобы избежать несоответствия между «прямыми» объявлениями и их определениями, поместите объявления в файл заголовка и включите этот файл заголовка как в исходные файлы определения, так и с использованием объявлений.
Однако в этом особом случае, когда только объявлен только непрозрачный класс, это прямое объявление может быть приемлемо для использования, но в целом, «использовать прямые объявления вместо включений, когда это возможно», как заголовокэта ветка говорит, что может быть довольно рискованной.
Вот несколько примеров «невидимых рисков», касающихся форвардных объявлений (невидимые риски = несоответствия объявлений, которые не обнаружены компилятором или компоновщиком):
Явные прямые декларации символов, представляющих данные, могут быть небезопасными, поскольку для таких прямых деклараций может потребоваться правильное знание размера (размера) типа данных.
Явная пересылкаобъявления символов, представляющих функции, также могут бытьнебезопасные, такие как типы параметров и количество параметров.
Пример, показанный ниже, иллюстрирует это, например, два опасных предварительных объявления данных, а также функции:
Файл ac:
#include <iostream>
char data[128][1024];
extern "C" void function(short truncated, const char* forgotten) {
std::cout << "truncated=" << std::hex << truncated
<< ", forgotten=\"" << forgotten << "\"\n";
}
Файл bc:
#include <iostream>
extern char data[1280][1024]; // 1st dimension one decade too large
extern "C" void function(int tooLarge); // Wrong 1st type, omitted 2nd param
int main() {
function(0x1234abcd); // In worst case: - No crash!
std::cout << "accessing data[1270][1023]\n";
return (int) data[1270][1023]; // In best case: - Boom !!!!
}
Компиляция программы с g ++ 4.7.1:
> g++ -Wall -pedantic -ansi a.c b.c
Примечание: Невидимая опасность, так как g ++не выдает ошибок / предупреждений компилятора или компоновщика
Примечание: пропуск extern "C"
приводит к ошибке компоновки function()
из-за искажения имени в c ++.
Запуск программы:
> ./a.out
truncated=abcd, forgotten="♀♥♂☺☻"
accessing data[1270][1023]
Segmentation fault