Почему форвард-декларирование необходимо в C ++
Компилятор хочет убедиться, что вы не допустили орфографических ошибок или передали неправильное количество аргументов функции. Таким образом, он настаивает на том, что сначала видит объявление 'add' (или любых других типов, классов или функций) перед его использованием.
Это на самом деле просто позволяет компилятору лучше выполнять проверку кода и позволяет ему убирать свободные концы, чтобы он мог создавать аккуратный объектный файл. Если вам не нужно пересылать объявленные вещи, компилятор создаст объектный файл, который должен будет содержать информацию обо всех возможных предположениях относительно того, какой может быть функция add. И компоновщик должен был бы содержать очень умную логику, чтобы попытаться определить, какое «add» вы на самом деле намеревались вызвать, когда функция «add» может находиться в другом объектном файле, который компоновщик объединяет с тем, который использует add для создания DLL или Exe. Возможно, что компоновщик может получить неправильное добавление. Скажем, вы хотели использовать int add (int a, float b), но случайно забыли написать его, но компоновщик нашел уже существующий int add (int a, б) и подумал, что это правильно, и использовал это вместо этого. Ваш код будет компилироваться, но не будет делать то, что вы ожидали.
Таким образом, просто для того, чтобы все было ясно, чтобы не было догадок и т. Д., Компилятор настаивает на том, чтобы вы объявляли все перед использованием.
Разница между декларацией и определением
Кроме того, важно знать разницу между объявлением и определением. Объявление просто дает достаточно кода, чтобы показать, как что-то выглядит, поэтому для функции это тип возвращаемого значения, соглашение о вызове, имя метода, аргументы и их типы. Но код для метода не требуется. Для определения вам нужно объявление, а затем и код для функции.
Как предварительные декларации могут значительно сократить время сборки
Вы можете получить объявление функции в вашем текущем файле .cpp или .h, # включив заголовок, который уже содержит объявление функции. Тем не менее, это может замедлить компиляцию, особенно если вы #include заголовка в .h вместо .cpp вашей программы, так как все, что включает в себя #inch .h вы пишете, в конечном итоге # include'ing все заголовки Вы тоже написали #includes для. Внезапно, компилятор имеет включенные # страницы и страницы кода, которые ему нужно скомпилировать, даже если вы хотите использовать только одну или две функции. Чтобы избежать этого, вы можете использовать предварительное объявление и просто ввести объявление функции в верхней части файла. Если вы используете только несколько функций, это действительно может сделать ваши компиляции быстрее, чем всегда, включая заголовок. Для действительно больших проектов,
Разорвать циклические ссылки, где два определения оба используют друг друга
Кроме того, предварительные декларации могут помочь вам разорвать циклы. Здесь две функции пытаются использовать друг друга. Когда это происходит (и это совершенно правильно), вы можете #include один заголовочный файл, но этот заголовочный файл пытается #include заголовочный файл, который вы сейчас пишете .... который затем #include другой заголовок , который включает в себя тот, который вы пишете. Вы застряли в ситуации курицы и яйца, когда каждый заголовочный файл пытается включить другой. Чтобы решить эту проблему, вы можете заранее объявить нужные вам части в одном из файлов и оставить #include вне этого файла.
Например:
Файл Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
Файл Wheel.h
Хм ... здесь требуется объявление Car, так как в Wheel есть указатель на Car, но Car.h не может быть здесь включен, так как это приведет к ошибке компилятора. Если был включен Car.h, то он попытался бы включить Wheel.h, который включал бы Car.h, который включал бы Wheel.h, и это продолжалось бы вечно, поэтому вместо этого компилятор вызывает ошибку. Решение состоит в том, чтобы направить объявление об автомобиле вместо:
class Car; // forward declaration
class Wheel
{
Car* car;
};
Если бы у класса Wheel были методы, которые должны вызывать методы car, эти методы можно было бы определить в Wheel.cpp, и теперь Wheel.cpp может включать Car.h без вызова цикла.