stringtranslate.com

Форвардная декларация

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

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

Форвардное объявление используется в языках, которые требуют объявления перед использованием; это необходимо для взаимной рекурсии в таких языках, так как невозможно определить такие функции (или структуры данных) без прямой ссылки в одном определении: одна из функций (соответственно структур данных) должна быть определена первой. Также полезно обеспечить гибкую организацию кода, например, если вы хотите разместить основную часть вверху, а вызываемые функции — под ней.

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

Примеры

Базовый пример на языке C:

void printThisInteger ( int ); 

В C и C++ строка выше представляет собой предварительное объявление функции и является ее прототипом . После обработки этого объявления компилятор разрешит программному коду ссылаться на объект printThisIntegerв остальной части программы. Определение функции должно быть где-то предоставлено (тот же файл или другой, где компоновщик будет обязан правильно сопоставить ссылки на конкретную функцию в одном или нескольких объектных файлах с определением, которое должно быть уникальным, в другом). :

void printThisInteger ( int x ) { printf ( "%d \n " , x ); }     

Переменные могут иметь только предварительное объявление и не иметь определения. Во время компиляции они инициализируются правилами, специфичными для языка (неопределенными значениями, 0, указателями NULL, ...). Переменные, определенные в других исходных/объектных файлах, должны иметь предварительное объявление, указанное с помощью ключевого слова extern:

интервал фу ; //foo может быть определен где-то в этом файле extern int bar ; //бар должен быть определен в каком-то другом файле     

В Паскале и других языках программирования Вирта общим правилом является то, что все сущности должны быть объявлены перед использованием, и, таким образом, прямое объявление необходимо, например, для взаимной рекурсии. В C применяется то же общее правило, но за исключением необъявленных функций и неполных типов. Таким образом, в C можно (хотя и неразумно) реализовать пару взаимно рекурсивных функций следующим образом:

int first ( int x ) { if ( x == 0 ) return 1 ; иначе вернуть секунду ( x -1 ); // пересылаем ссылку на вторую }             int Second ( int x ) { if ( x == 0 ) return 0 ; иначе сначала вернитесь ( x -1 ); // обратная ссылка на первую }             

В Паскале та же реализация требует, чтобы предварительное объявление secondпредшествовало его использованию в first. Без предварительного объявления компилятор выдаст сообщение об ошибке, указывающее, что идентификатор использовался second без объявления.

Классы

В некоторых объектно-ориентированных языках, таких как C++ и Objective-C , иногда необходимо предварительно объявлять классы. Это делается в ситуациях, когда необходимо знать, что имя класса является типом, но когда знать структуру необязательно.

В C++ классы и структуры могут быть объявлены заранее следующим образом:

класс МойКласс ; структура MyStruct ;  

В C++ классы могут быть объявлены вперед, если вам нужно использовать только тип указателя на этот класс (поскольку все указатели на объекты имеют одинаковый размер, и это то, о чем заботится компилятор). Это особенно полезно внутри определений классов, например, если класс содержит член, который является указателем (или ссылкой) на другой класс.

Упреждающее объявление используется, чтобы избежать ненужной связи, что помогает сократить время компиляции за счет уменьшения количества включений заголовков. Это имеет тройное преимущество:

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

В Objective-C классы и протоколы могут быть объявлены заранее следующим образом:

@класс  МойКласс ; @протокол  МойПротокол ;

В Objective-C классы и протоколы могут быть объявлены вперед, если вам нужно использовать их только как часть типа указателя объекта, например MyClass * или id<MyProtocol> . Это особенно полезно внутри определений классов, например, если класс содержит член, который является указателем на другой класс; Чтобы избежать циклических ссылок (т. е. этот класс может также содержать член, который является указателем на этот класс), вместо этого мы просто объявляем классы вперед.

Предварительного объявления класса или протокола недостаточно, если вам нужно создать подкласс этого класса или реализовать этот протокол.

Прямая ссылка

Термин «передовая ссылка» иногда используется как синоним « форвардного объявления» . [1] Однако чаще всего используется ссылка на фактическое использование объекта перед каким-либо объявлением; то есть первая ссылка на secondв приведенном выше коде является прямой ссылкой. [2] [3] Таким образом, мы можем сказать, что, поскольку в Паскале обязательные объявления вперед, ссылки вперед запрещены.

Пример (действительной) прямой ссылки в C++ :

класс C { public : void mutator ( int x ) { myValue = x ; } Int Accessor () const { return myValue ; } Частное : int myValue ; };                   

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

Разрешение прямых ссылок может значительно увеличить сложность и требования к памяти компилятора и, как правило, не позволяет реализовать компилятор за один проход .

Рекомендации

  1. ^ MSDN: преобразование в тип класса с прямой ссылкой
  2. ^ http://pages.cs.wisc.edu/~fischer/cs536.s07/lectures/Lecture25.4up.pdf [ пустой URL-адрес PDF ]
  3. ^ Мышление на C++: встроенные строки и компилятор