Из Википедии, свободной энциклопедии
  (Перенаправлено из прямой ссылки )
Перейти к навигации Перейти к поиску

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

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

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

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

Примеры [ править ]

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

void  printThisInteger ( int );

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

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

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

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

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

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

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

Классы [ править ]

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

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

класс  MyClass ; struct  MyStruct ;

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

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

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

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

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

@class  MyClass ;@protocol  MyProtocol ;

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

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

Прямая ссылка [ править ]

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

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

class  C  { public :  void  mutator ( int  x )  {  myValue  =  x ;  }  int  accessor ()  const  {  return  myValue ;  } private :  int  myValue ; };

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

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

Ссылки [ править ]