Declaración de funciones

De EcuRed
Declaración de funciones
Información sobre la plantilla
Concepto:Da a conocer la función al compilador, de forma que a partir del punto de declaración, ya se pueden realizar invocaciones a la misma

Declaración de funciones. La declaración da a conocer la función al compilador, de forma que a partir del punto de declaración, ya se pueden realizar invocaciones a la misma. A su vez, la definición estará en algún otro punto del programa, tal vez en una librería externa (en forma ya compilada) o en otro módulo de programa (como texto fuente). Una función puede ser declarada varias veces en un mismo programa, y las declaraciones pueden aparecer en cualquier orden; en un fichero fuente o en varios, pero en cualquier caso antes de su uso, es decir: antes de cualquier invocación a la función. Además de declarar el nombre de la función y el tipo devuelto (por defecto se supone int) se declaran también el tipo de los parámetros.

Contenido

Sintaxis:

[extern] <tipo-devuelto> nombre-funcion ()                // §2a
[extern] <tipo-devuelto> nombre-funcion (<tipo>, ...)     // §2b
[extern] <tipo-devuelto> nombre-funcion (<tipo> <parametro>, ... ) // §2c

Ejemplos:

extern int funcion1 ();      // no acepta ningún argumento
extern int funcion1 (void);  // mejor que la anterior
funcion2 (char, int);        // por defecto supone que devuelve  int
int funcion2 (char, int);     // mejor que la anterior
char funcion3 (char c, int i); // incluye nombres de parámetros

Comentario

  • El especificador <tipo-devuelto> es opcional. Por defecto se supone int, así que las declaraciones que siguen son equivalentes:
int func (<tipo> <parámetro>, ...)
func (<tipo> <parámetro>, ...)

Los compiladores MS Visual C++ y Borland C++ admiten que ciertos especificadores opcionales acompañen a la declaración de funciones y otros objetos. Tales especificadores son de utilidad en circunstancias específicas.

Declaraciones

Las declaraciones deben realizarse antes que cualquier uso de la función. A su vez, las definiciones pueden estar en cualquier sitio, aunque en algunos casos puede haber excepciones (sustitución inline). Las declaraciones de funciones tienen un nombre específico: se denominan prototipo. El primero de los anteriores (§2a) es válido, aunque desaconsejado (herencia del C); es el denominado estilo clásico Kernighan & Ritchie. El segundo (§2b) y tercero (§2c), son los aceptados en C++. En la declaración de parámetros no está permitido incluir funciones, es decir, las funciones no pueden pasar como argumentos a otras funciones. Sin embargo, C++ dispone de recursos cuando esto es necesario; pasar un puntero o una referencia a la función.

El viejo estilo K&R tiene la desventaja de no permitir al compilador comprobar el número y tipo de los argumentos utilizados en las llamadas a la función. Este problema fue eliminado con la introducción de los prototipos que utilizan la forma completa, en la que se especifica el número y tipo de cada argumento aceptado por la función. El compilador usa estos datos para comprobar la validez de las llamadas a la función y como se ilustra en el ejemplo, es capaz en su caso, de realizar dentro de ciertos límites, un modelado de tipo ("Casting") de los argumentos para garantizar que coinciden con el tipo esperado.

El mecanismo anterior permite al compilador efectuar una comprobación de tipos de los argumentos que pasan y del valor devuelto. Los lenguajes en los que no se realizan estas comprobaciones, se denominan de débilmente tipados ("Weakly typed"), tienen la desventaja de que no conocen exactamente el tipo de código que ejecutarán.

Las funciones tienen ámbito global, y sus declaraciones (prototipos) aunque suelen estar al principio (inmediatamente después de las directivas de preprocesado), pueden aparecer en cualquier parte del fichero. Ponerlas al principio tiene la ventaja de que sus nombres sean conocidos en la totalidad del fichero, con lo que pueden ser invocadas desde cualquier punto -desde cualquier otra función, incluso main- sin tener que declarar un prototipo dentro de cada función que las invoque.

Prototipos de funciones

Los prototipos juegan un rol importante en la programación C++ y sirven también para clarificar y documentar el código. Sobre todo si los nombres de las variables son significativos. Por ejemplo, la función strcpy tiene dos parámetros: una cadena fuente y una destino, la cuestión es: ¿Cual es cual?

char *strcpy(char* dest, const char* source);

Si se incluye un identificador en el parámetro de un prototipo, solo es utilizado para los posibles mensajes de error relativos a tal parámetro sin ningún otro efecto. De hecho, los identificadores (nombres) de los parámetros suelen ser largos y descriptivos en los prototipos, mientras que en las definiciones suelen ser abreviados, sin que, en este aspecto, tengan que haber coincidencia entre ambos. Esto significa que en realidad los nombres de los argumentos no son imprescindibles en los prototipos; solo son necesarios los tipos de los parámetros. Es decir, el prototipo de la función anterior podría perfectamente ser sustituido por:

char *strcpy(char*, const char*);

Un declarador de función con la palabra void entre paréntesis: func(void);, indica que la función no acepta ningún parámetro. Es equivalente a la expresión como func();, que también declara una función sin parámetros.

Prototipos y ficheros de cabecera

Es costumbre que los prototipos de las funciones incluidas en las librerías del lenguaje se agrupen en ficheros específicos, los denominados ficheros de cabecera ("header files"), que son ficheros de texto en los que se agrupan todas las declaraciones utilizadas en la librería.

También es frecuente que los programadores C++ construyan sus propias librerías que acompañan a las que vienen preconstruidas en el lenguaje. Para ello se agrupan en ciertos módulos aquellas funciones o clases más frecuentemente utilizadas. Estos módulos son compilados y enlazados de una forma especial de forma que no se obtiene un ejecutable, sino una librería de las que existen varios tipos. En cualquier caso, sean librerías preconstruidas en el lenguaje o de fabricación propia, los prototipos de las funciones incluidas en ellas se agrupan en ficheros de cabecera. Las que vienen con el lenguaje se localizan en el directorio \Include; las de fabricación propia se deben mantener en otro directorio distinto del anterior.

Puesto que es imprescindible incluir en cada fichero fuente la declaración de cada función antes de que pueda ser utilizada, el hecho de tener agrupadas las declaraciones en un fichero de cabecera es de gran utilidad, porque solo es preciso incluir una directiva include al principio de cada fuente para tener la seguridad de que todos los prototipos estarán presentes. De otro modo tendría que escribirlos manualmente en cada fuente que utilizara funciones de la librería.

Número variable de argumentos

Normalmente los prototipos de funciones declaran un número fijo de parámetros (que puede ser ninguno). Para las funciones que pueden aceptar un número variable de parámetros (tales como printf), el prototipo puede terminar en puntos suspensivos (...). Esta elipsis indica que la función puede ser invocada con diferentes tipos de argumentos en diferentes ocasiones. Los puntos pueden colocarse al final de una sublista de parámetros conocidos. Por ejemplo: func(int *count, long total, ...); Esta forma de prototipo reduce la comprobación que puede efectuar el compilador; los parámetros fijos son comprobados en tiempo de compilación, y los variables son pasados sin comprobación.

Polimorfismo

Aparte de estas tareas de comprobación y modelado de tipos, en realidad el objetivo principal de incluir en la declaración de funciones una descripción detallada del valor devuelto y de los parámetros aceptados, es permitir lo que se llama sobrecarga (de funciones). Esto significa que dentro del mismo ámbito puedan definirse varias funciones con nombres idénticos, pero distintos parámetros y por supuesto distintas definiciones. Más tarde, el compilador será capaz de saber a cual de ellas nos estamos refiriendo, precisamente analizando los parámetros que pasamos a la función. Por ejemplo, en C++ está permitido el siguiente trozo de código:

int alfa (int deg, int min, int sec); // declaracion-1 de alfa
void alfa (int deg);                  // declaracion-2 de alfa
int alfa (char n);                    // declaracion-3 de alfa
  ...
n = alfa('c');                        // invocación de alfa-3

El compilador conoce que, en este caso, la invocación se refiere a la tercera declaración de la función alfa, precisamente por el argumento utilizado. Las funciones main, WinMain y LibMain no pueden ser sobrecargadas. Ejemplo:

extern "C" void WinMain(int, char*, char*);
void WinMain(int, short, char*, char*);       // Error!!

Puede Contactar

Fuente