Punteros a funciones
Tanto en C como en C++ se pueden declarar punteros a funciones.
Sintaxis:
<tipo> (*<identificador>)(<lista_de_parámetros>); |
De esta forma se declara un puntero a una función que devuelve un valor de tipo <tipo> y acepta la lista de parámetros especificada. Es muy importante usar los paréntesis para agrupar el asterisco con el identificador, ya que de otro modo estaríamos declarando una función que devuelve un puntero al tipo especificado y que admite la lista de parámetros indicada.
No tiene sentido declarar variables de tipo función, es decir, la sintaxis indicada, prescindiendo del '*' lo que realmente declara es un prototipo, y no es posible asignarle un valor a un prototipo, como se puede hacer con los punteros, sino que únicamente podremos definir la función.
Ejemplos:
int (*pfuncion1)(); (1) void (*pfuncion2)(int); (2) float *(*pfuncion3)(char*, int); (3) void (*pfuncion4)(void (*)(int)); (4) int (*pfuncion5[10])(int); (5) |
El ejemplo 1 declara un puntero, "pfuncion1" a una función que devuelve un int y no acepta parámetros.
El ejemplo 2 declara un puntero, "pfuncion2" a una función que no devuelve valor y que acepta un parámetro de tipo int.
El ejemplo 3 a una función que devuelve un puntero a float y admite dos parámetros: un puntero a char y un int.
El 4, declara una función "pfuncion4" que no devuelve valor y acepta un parámetro. Ese parámetro debe ser un puntero a una función que tampoco devuelve valor y admite como parámetro un int.
El 5 declara un array de punteros a función, cada una de ellas devuelve un int y admite como parámetro un int.
Este otro ejemplo:
int *(pfuncionx)(); Equivale a: int *pfuncionx(); |
Que, claramente, es una declaración de un prototipo de una función que devuelve un puntero a int y no admite parámetros.
Utilidad de los punteros a funciones
La utilidad de los punteros a funciones se manifiesta sobre todo cuando se personalizan ciertas funciones de biblioteca. Podemos por ejemplo, diseñar una función de biblioteca que admita como parámetro una función, que debe crear el usuario (en este caso otro programador), para que la función de biblioteca complete su funcionamiento.
Este es el caso de la función qsort, declarada en cstdlib. Si nos fijamos en su prototipo:
void qsort(void *base, size_t nmemb, size_t tamanyo, int (*comparar)(const void *, const void *)); |
Vemos que el cuarto parámetro es un puntero a una función comparar que devuelve un int y admite dos parámetros de tipo puntero genérico.
Esto permite a la biblioteca cstdib definir una función para ordenar arrays independientemente de su tipo, ya que para comparar elementos del array se usa una función definida por el usuario, y qsort puede invocarla después.
Asignación de punteros a funciones
Una vez declarado uno de estos punteros, se comporta como una variable cualquiera, podemos por lo tanto, usarlo como parámetro en funciones, o asignarle valores, por supuesto, del mismo tipo.
int funcion(); ... int (*pf1)(); // Puntero a función sin argumentos // que devuelve un int. pf1 = funcion; // Asignamos al puntero pf1 la // función "funcion" ... int funcion() { return 1; } |
La asignación es tan simple como asignar el nombre de la función.
Nota: Aunque muchos compiladores lo admiten, no es recomendable aplicar el operador de dirección (&) al nombre de la función pf1 = &funcion;. La forma propuesta en el ejemplo es la recomendable. |
Llamadas a través de un puntero a función
Para invocar a la función usando el puntero, sólo hay que usar el identificador del puntero como si se tratase de una función. En realidad, el puntero se comporta exactamente igual que un "alias" de la función a la que apunta.
int x = pf1(); |
De este modo, llamamos a la función "funcion" previamente asignada a *pf1.
Ejemplo completo:
#include <iostream> using namespace std; int Muestra1(); int Muestra2(); int Muestra3(); int Muestra4(); int main() { int (*pf1)(); // Puntero a función sin argumentos que devuelve un int. int num; do { cout << "Introduce un número entre 1 y 4, " << "0 para salir: "; cin >> num; if(num >= 1 && num <=4) { switch(num) { case 1: pf1 = Muestra1; break; case 2: pf1 = Muestra2; break; case 3: pf1 = Muestra3; break; case 4: pf1 = Muestra4; break; } pf1(); } } while(num != 0); return 0; } int Muestra1() { cout << "Muestra 1" << endl; return 1; } int Muestra2() { cout << "Muestra 2" << endl; return 2; } int Muestra3() { cout << "Muestra 3" << endl; return 3; } int Muestra4() { cout << "Muestra 4" << endl; return 4; } |
Otro ejemplo:
#include <iostream> using namespace std; int Fun1(int); int Fun2(int); int Fun3(int); int Fun4(int); int main() { int (*pf1[4])(int); // Array de punteros a función con un // argumento int que devuelven un int. int num; int valores; pf1[0] = Fun1; pf1[1] = Fun2; pf1[2] = Fun3; pf1[3] = Fun4; do { cout << "Introduce un número entre 1 y 4, " << "0 para salir: "; cin >> num; if(num >= 1 && num <=4) { cout << "Introduce un número entre 1 y 10: "; cin >> valores; if(valores > 0 && valores < 11) pf1[num-1](valores); } } while(num != 0); return 0; } int Fun1(int v) { while(v--) cout << "Muestra 1" << endl; return 1; } int Fun2(int v) { while(v--) cout << "Muestra 2" << endl; return 2; } int Fun3(int v) { while(v--) cout << "Muestra 3" << endl; return 3; } int Fun4(int v) { while(v--) cout << "Muestra 4" << endl; return 4; } |
Palabras reservadas usadas en este capítulo
inline.
Capitulo 21 | Ir al Principio
Comentarios