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

tp://www.learncpp.com/cpp-tutorial/19-header-files/Упоминается следующее:

add.cpp:

main.cpp:

int add(int x, int y)
{
    return x + y;
}

Мы использовали предварительное объявление, чтобы компилятор знал, что "

#include <iostream>

int add(int x, int y); // forward declaration using function prototype

int main()
{
    using namespace std;
    cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
    return 0;
}

был при компиляцииadd, Как упоминалось ранее, написание предварительных объявлений для каждой функции, которую вы хотите использовать и которая находится в другом файле, может быстро утомить.main.cppВы можете объяснить "

предварительная декларация«Далее? В чем проблема, если мы используем его в функционировать?main()«Предварительная декларация» на самом деле просто декларация. Смотрите (конец) этого ответа:

 sbi21 янв. 2011 г., 11:33

Ответы на вопрос(8)

int add(int x, int y); // forward declaration using function prototype

, Если вы знаете, препроцессор расширяет файл, который вы упоминаете в#include"add.h"в .cpp файле, где вы пишете#include директивы. Это означает, что если вы напишите#includeвы получаете то же самое, как если бы вы делали «предварительное объявление».#include"add.h"Я предполагаю что

 имеет эту строку:add.hодно быстрое дополнение, касающееся: обычно вы помещаете эти прямые ссылки в заголовочный файл, принадлежащий файлу .c (pp), где реализована функция / переменная и т. д. в вашем примере это будет выглядеть так: add.h:

int add(int x, int y); 

  что это значит. С помощью предварительного объявления вы в основном сообщаете компилятору, чтоadd(3, 4) это функция, которая принимает два целых числа и возвращает целое число Это важная информация для компилятора, потому что он должен поместить 4 и 5 в правильном представлении в стек и должен знать, что это за тип, возвращаемый add.addВ то время компилятор не беспокоился о

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

  но это может быть как правильно, так и неправильно. Другая проблема заключается в том, что компилятор не знает, какого рода аргументы ожидает ваша функция, и не может предупредить вас, если вы передаете значения неправильного типа. Существуют специальные правила «продвижения», которые применяются при передаче, скажем, значений с плавающей запятой в необъявленную функцию (компилятор должен расширить их до типа double), что часто не соответствует ожиданиям функции, что приводит к трудностям в поиске ошибок. во время выполнения.intЧто такое предварительные объявления в

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

int add( int x, int y )

Так что

Форвардная декларацияэто то, что написано на банке. Он объявляет что-то перед его использованием.Как правило, вы должны включить предварительные объявления в файл заголовка, а затем включить этот файл заголовка так же, как

iostream Включено.Термин "

"в C ++ в основном используется только дляобъявления класса, Смотри (конец)этот ответ почему «предварительное объявление» класса на самом деле простообъявление класса с причудливым именем.Другими словами, «вперед» просто добавляет балласт к термину, так как

Любые объявление можно рассматривать как пересылку, поскольку оно объявляет некоторый идентификатордо Это использовано.(Что касается того, что является

декларация в отличие отопределениеопять увидимВ чем разница между определением и декларацией?Когда компилятор видит)

что функция фактически объявлена во внешнем файле (также может быть библиотекой и т. д.). ваш main.c будет выглядеть так:

extern int add(int a, int b);

Но разве мы не помещаем объявления только в заголовочный файл? Я думаю, именно поэтому функция определена в "add.cpp", и, следовательно, с использованием предварительных объявлений? Благодарю.

#include 
#include "add.h"

int main()
{
.
.
.

 Simplicity21 янв. 2011 г., 11:52
Одна проблема заключается в том, что компилятор не знает, какое значение доставляет ваша функция; is предполагает, что функция возвращает
Решение Вопроса

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

Это на самом деле просто позволяет компилятору лучше выполнять валидацию кода и позволяет ему убирать свободные концы, чтобы он мог создать аккуратный объектный файл. Если вам не нужно пересылать объявленные вещи, компилятор создаст объектный файл, который должен будет содержать информацию обо всех возможных предположениях относительно того, какой может быть функция add. И компоновщик должен был бы содержать очень умную логику, чтобы попытаться определить, какое «add» вы на самом деле намеревались вызвать, когда функция «add» может находиться в другом объектном файле, который компоновщик объединяет с тем, который использует add для создания DLL или Exe. Возможно, что компоновщик может получить неправильное добавление. Скажем, вы хотели использовать int add (int a, float b), но случайно забыли написать его, но компоновщик нашел уже существующий int add (int a, int b) и подумал, что он правильный, и использовал его вместо этого. Ваш код будет компилироваться, но не будет делать то, что вы ожидали.

Таким образом, просто для того, чтобы все было ясно, чтобы избежать догадок и т. Д., Компилятор настаивает на том, чтобы вы объявляли все, прежде чем его использовать.

Разница между декларацией и определением

Кроме того, важно знать разницу между объявлением и определением. Объявление просто дает достаточно кода, чтобы показать, как что-то выглядит, поэтому для функции это тип возвращаемого значения, соглашение о вызове, имя метода, аргументы и их типы. Но код для метода не требуется. Для определения вам нужно объявление, а затем и код для функции.

Как предварительные декларации могут значительно сократить время сборки

Вы можете получить объявление функции в вашем текущем файле .cpp или .h, # включив заголовок, который уже содержит объявление функции. Тем не менее, это может замедлить компиляцию, особенно если вы #include заголовка в .h вместо .cpp вашей программы, так как все, что #include .h вы пишете, в конечном итоге # include'ing все заголовки Вы тоже написали #includes для. Внезапно компилятор имеет #included страницы и страницы кода, которые ему нужно скомпилировать, даже если вы хотите использовать только одну или две функции. Чтобы избежать этого, вы можете использовать предварительную декларацию и просто ввести объявление функции в верхней части файла. Если вы используете только несколько функций, это действительно может сделать ваши компиляции быстрее, чем всегда, включая заголовок. Для действительно больших проектов разница может составлять час или больше времени компиляции, сокращенного до нескольких минут.

Разорвать циклические ссылки, где два определения оба используют друг друга

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

Например:

Файл Car.h

Файл Wheel.h

#include "Wheel.h"  // Include Wheel's definition so it can be used in Car.
#include <vector>

class Car
{
    std::vector<Wheel> wheels;
};

Хм ... здесь требуется объявление Car, так как в Wheel есть указатель на Car, но Car.h не может быть здесь включен, так как это приведет к ошибке компилятора. Если был включен Car.h, то он попытался бы включить Wheel.h, который включал бы Car.h, который включал бы Wheel.h, и это продолжалось бы вечно, поэтому вместо этого компилятор вызывает ошибку. Решение состоит в том, чтобы направить объявление об автомобиле вместо:

Если бы в классе Wheel были методы, которые должны вызывать методы car, эти методы могли бы быть определены в Wheel.cpp, и теперь Wheel.cpp может включать Car.h без вызова цикла.

class Car;     // forward declaration

class Wheel
{
    Car* car;
};

предварительное объявление также необходимо, когда функция дружественна двум или нескольким классам.

 Zepee11 февр. 2015 г., 20:28
@Zepee Это баланс. Для быстрых сборок я бы сказал, что это хорошая практика, и я рекомендую попробовать ее. Однако это может потребовать некоторых усилий и дополнительных строк кода, которые, возможно, потребуется поддерживать и обновлять, если имена типов и т. Д. Все еще изменяются (хотя инструменты становятся лучше в переименовании вещей автоматически). Таким образом, есть компромисс. Я видел кодовые базы, где никто не беспокоится. Если вы обнаружите, что повторяете одни и те же форвардные определения, вы всегда можете поместить их в отдельный заголовочный файл и включить в него что-то вроде:
 Dagrooms15 июн. 2017 г., 21:57
 тогда вы можете создать некоторые опасные ситуации, пытаясь найти определение в будущем, гарантировано.// From Car.hКомпилятор ищет каждый символ, используемый в текущей единице перевода, ранее объявленной или нет в текущей единице. Это просто вопрос стиля, предоставляющий все сигнатуры методов в начале исходного файла, а определения будут предоставлены позже. Значительное использование этого происходит, когда вы используете указатель на класс в качестве переменной-члена другого класса.
 Barun17 сент. 2014 г., 13:13
Привет, Скотт, что касается времени сборки: скажете ли вы, что это обычная / лучшая практика - всегда пересылать объявления и включать заголовки по мере необходимости в файл .cpp? После прочтения вашего ответа может показаться, что так и должно быть, но мне интересно, есть ли какие-то предостережения?

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

//foo.h
class bar;    // This is useful
class foo
{
    bar* obj; // Pointer or even a reference.
};

// foo.cpp
#include "bar.h"
#include "foo.h"

Поскольку C ++ анализируется сверху вниз, компилятор должен знать о вещах, прежде чем они будут использованы. Итак, когда вы ссылаетесь:

Ваш ответ на вопрос