Articulo de referencia

Declaración anticipada

En programación informática , una declaración anticipada es la declaración de un identificador (que denota una entidad como un tipo, una variable, una constante o una función) p...

En programación informática , una declaración anticipada es la declaración de un identificador (que denota una entidad como un tipo, una variable, una constante o una función) para la cual el programador aún no ha dado una definición completa .

Es necesario que un compilador conozca ciertas propiedades de un identificador (tamaño para la asignación de memoria , tipo de dato para la verificación de tipos , como la firma de tipo de las funciones), pero no es necesario que conozca otros detalles, como el valor específico que contiene (en el caso de variables o constantes) o su definición (en el caso de funciones). Esto resulta especialmente útil para compiladores de una sola pasada y compilación separada .

La declaración anticipada se utiliza en lenguajes que requieren la declaración previa al uso; es necesaria para la recursión mutua en dichos lenguajes, ya que es imposible definir funciones (o estructuras de datos) sin una referencia anticipada en una de las definiciones: una de las funciones (o estructuras de datos) debe declararse primero. También resulta útil para permitir una organización flexible del código, por ejemplo, si se desea colocar el cuerpo principal al principio y las funciones llamadas debajo.

En otros lenguajes, las declaraciones anticipadas no son necesarias, lo que generalmente requiere un compilador de múltiples pasadas y que, en algunos casos, la compilación se posponga hasta el tiempo de enlace . En estos casos, los identificadores deben definirse (variables inicializadas, funciones definidas) antes de que puedan utilizarse durante la ejecución, sin necesidad de una predefinición en el código fuente para la compilación o la interpretación: los identificadores no necesitan resolverse inmediatamente a una entidad existente.

Ejemplos

Un ejemplo básico en C es:

void printThisInteger ( int );

En C y C++ , la línea anterior representa una declaración anticipada de una función y es su prototipo . Tras procesar esta declaración, el compilador permite que el código del programa haga referencia a la entidad printThisIntegeren el resto del programa. La definición de una función debe proporcionarse en algún lugar (en el mismo archivo o en otro, donde el enlazador se encarga de hacer coincidir correctamente las referencias a una función específica en uno o varios archivos objeto con la definición, que debe ser única, en otro archivo):

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

Las variables solo pueden tener declaración anticipada y carecer de definición. Durante la compilación, se inicializan mediante reglas específicas del lenguaje (con valores indefinidos, 0, punteros NULL, etc.). Las variables definidas en otros archivos fuente/objeto deben tener una declaración anticipada especificada con una palabra clave extern:

int foo ; //foo podría estar definido en algún lugar de este archivo extern int bar ; //bar debe estar definido en algún otro archivo

En Pascal y otros lenguajes de programación de Wirth , es regla general que todas las entidades deben declararse antes de su uso, por lo que la declaración anticipada es necesaria para la recursión mutua, por ejemplo. En C, se aplica la misma regla general, pero con una excepción para las funciones no declaradas y los tipos incompletos. Por lo tanto, en C es posible (aunque no recomendable) implementar un par de funciones mutuamente recursivas de la siguiente manera:

int first ( int x ) { if ( x == 0 ) return 1 ; else return second ( x - 1 ); // referencia anticipada a second }int segundo ( int x ) { if ( x == 0 ) return 0 ; else return primero ( x - 1 ); // referencia hacia atrás a primero }

En Pascal, la misma implementación requiere una declaración anticipada para secondpreceder su uso en first. Sin la declaración anticipada, el compilador generará un mensaje de error que indica que el identificadorsecond se ha utilizado sin haber sido declarado.

Clases

En algunos lenguajes orientados a objetos, como C++ y Objective-C , a veces es necesario declarar clases por adelantado. Esto se hace cuando es necesario saber que el nombre de la clase es un tipo, pero no es necesario conocer su estructura.

En C++, las clases y las estructuras se pueden declarar de forma anticipada de esta manera:

clase MyClass ; estructura MyStruct ;

En C++, las clases se pueden declarar anticipadamente si solo se necesita usar el puntero a esa clase (ya que todos los punteros a objetos tienen el mismo tamaño, y esto es lo que le importa al compilador). Esto es especialmente útil dentro de las definiciones de clase, por ejemplo, si una clase contiene un miembro que es un puntero (o una referencia) a otra clase.

La declaración anticipada se utiliza para evitar el acoplamiento innecesario, lo que ayuda a reducir el tiempo de compilación al disminuir la cantidad de inclusiones de encabezado. Esto tiene una triple ventaja:

  • reducir el número de archivos abiertos por #include (y por lo tanto, el número de llamadas al sistema operativo )
  • reduciendo el volumen de los archivos preprocesados ​​(ya que no se incluye el encabezado)
  • reducir el impacto de la recompilación cuando se modifica la clase declarada previamente.

La declaración anticipada de una clase no es suficiente si necesita usar el tipo de clase real, por ejemplo, si tiene un miembro cuyo tipo es esa clase directamente (no un puntero), o si necesita usarla como clase base, o si necesita usar los métodos de la clase en un método.

En Objective-C, las clases y los protocolos se pueden declarar de forma anticipada de esta manera:

@class MyClass ; @protocol MyProtocol ; 

En Objective-C, las clases y los protocolos se pueden declarar de forma anticipada si solo se necesitan como parte de un tipo de puntero a objeto, por ejemplo, `MyClass *` o `id<MyProtocol> `. Esto es especialmente útil dentro de las definiciones de clase, por ejemplo, si una clase contiene un miembro que es un puntero a otra clase; para evitar referencias circulares (es decir, que esa clase también pueda contener un miembro que sea un puntero a esta clase), simplemente declaramos las clases de forma anticipada.

La declaración anticipada de una clase o protocolo no es suficiente si necesita crear una subclase de esa clase o implementar ese protocolo.

Referencia anticipada

El término referencia anticipada se usa a veces como sinónimo de declaración anticipada . [ 1 ] Sin embargo, con mayor frecuencia se refiere al uso real de una entidad antes de cualquier declaración; es decir, la primera referencia seconden el código anterior es una referencia anticipada. [ 2 ] [ 3 ] Por lo tanto, podemos decir que, dado que las declaraciones anticipadas son obligatorias en Pascal, las referencias anticipadas están prohibidas.

Un ejemplo de referencia anticipada (válida) en C++ :

clase C { público : void mutador ( int x ) { myValue = x ; } int accessor () const { return myValue ; } privado : int myValue ; };

En este ejemplo, hay dos referencias myValueantes de que se declare. C++ generalmente prohíbe las referencias anticipadas, pero se permiten en el caso especial de los miembros de clase. Dado que la función miembro accessorno se puede compilar hasta que el compilador conozca el tipo de la variable miembromyValue , es responsabilidad del compilador recordar la definición de accessorhasta que vea myValuela declaración de .

Permitir referencias anticipadas puede aumentar considerablemente la complejidad y los requisitos de memoria de un compilador, y generalmente impide que el compilador se implemente en una sola pasada .

Referencias

  1. MSDN: Conversión a un tipo de clase de referencia anticipada
  2. "Lección 25" (PDF) . Archivado del original (PDF) el 22 de mayo de 2011.
  3. "Pensando en C++: Inlines y el compilador" . Archivado del original el 4 de marzo de 2016. Consultado el 26 de octubre de 2015 .