Anuncios

Bienvenidos sean a este post, hoy continuaremos con el tema del post anterior y seguiremos el tema de apuntadores de funciones pero en este caso veremos apuntadores a un array de funciones. Veamoslo a traves del siguiente ejemplo:

static05.cpp

# include <iostream>

using namespace std;

void Cuadrado(int &, int &);
void Cubo(int &, int &);
void Intercambiar(int &, int &);
void ObtenerValores(int &, int &);
void ImprimirValores(int &, int &);

int main()
{
 	int valUno = 1, valDos = 2;
 	int opcion, i;
 	const int MaxArreglo = 5;
 	void (* apFuncArreglo[MaxArreglo]) (int &, int &);

	for (i = 0; i < MaxArreglo; i++)
 	{
 		cout << "(0)Salir (1)Cambiar Valores ";
		cout << "(2)Cuadrado (3)Cubo (4)Intercambiar:";
 		cin >> opcion;
		switch(opcion)
 		{
 			case 1:apFuncArreglo[i] = ObtenerValores; break;
 			case 2:apFuncArreglo[i] = Cuadrado; break;
 			case 3:apFuncArreglo[i] = Cubo; break;
 			case 4:apFuncArreglo[i] = Intercambiar; break;
 			default: apFuncArreglo[i] = 0;
 		}
	}

	for (i = 0; i < MaxArreglo; i++)
 	{
 		if (apFuncArreglo[i] == 0)
 			continue;
 		apFuncArreglo[i](valUno, valDos);
		ImprimirValores(valUno, valDos);
 	}	

	return 0;
}

void ImprimirValores(int & x, int & y)
{
 	cout << "x: " << x << " y: " << y << endl;
}

void Cuadrado(int & rX, int & rY)
{
 	rX *= rX;
 	rY *= rY;
}

void Cubo(int & rX, int & rY)
{
 	int tmp;
	tmp = rX;
 	rX *= rX;
 	rX = rX * tmp;
	tmp = rY;
 	rY *= rY;
 	rY = rY * tmp;
}

void Intercambiar(int & rX, int & rY)
{
 	int temp;
 	temp = rX;
 	rX = rY;
 	rY = temp;
}

void ObtenerValores(int & rValUno, int & rValDos)
{
 	cout << "Nuevo valor para valUno: ";
 	cin >> rValUno;
 	cout << "Nuevo valor para valDos: ";
 	cin >> rValDos;
}
Anuncios

Este ejemplo proviene del post anterior pero con algunas modificaciones, en el ejemplo anterior nosotros teniamos varias funciones, creabamos un apuntador para las funciones las cuales ibamos asignando a traves de un while donde nos preguntaba cual opcion queriamos elegir, y salia al elegir cero, en los case del switch es default, porque pasaba la variable fSalir en true, en este caso es muy parecido, vamos a tener los prototipos de las funciones a utilizar, luego pasando al main() vamos a declarar las variables a utilizar y asignarles un valor como en el caso de valUno, valDos y el valor constante de MaxArreglo, el resto no es necesario inicializarlas, luego vendra la creacion del apuntador del tipo array, es la siguiente linea:

void (* apFuncArreglo[MaxArreglo]) (int &, int &);
Anuncios

En la estructura es similar a como vimos en el ejemplo del post anterior, donde primero definimos el tipo a crear el cual debe ser coincidente con nuestras funciones, luego entre parentesis pondremos el nombre del apuntador con el asterisco (*) y entre corchetes el valor maximo del array, en este caso seteado por MaxArreglo que tiene un valor constante, y como nuestras funciones tienen dos valores enteros tambien lo declaramos. En el ejemplo de apuntador de funciones del post anterior, nosotros teniamos un while para ejecutar las funciones pero en este programa haremos una variacion, en este utilizaremos un bucle for establecido por MaxArreglo, en ella almacenaremos la opciones elegidas, observen como el switch, elegira en los case en base a la opcion elegida y esto lo asignara una funcion al apuntador de funciones salvo en el caso de default donde seteara el valor del apuntador en cero, y la posicion estara definida por el numero de vuelta del ciclo, en este caso por el incremento de la variable i. Una vez terminado el bucle for, utilizaremos otro bucle for donde tendra un condicional si el valor del apuntador es igual a cero saltara las acciones establecidas en el bucle por medio del continue, en caso contrario ejecutara la funcion almacenada en la posicion del array la cual sera llamada en base al valor del ciclo del bucle for. Una vez terminado el ciclo, se procedera a salir del programa, las funciones ya fueron explicadas en el post anterior. La salida es algo asi:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./static05
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar:1
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar:2
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar:0
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar:1
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar:3
Nuevo valor para valUno: 2 
Nuevo valor para valDos: 4
x: 2 y: 4
x: 4 y: 16
Nuevo valor para valUno: 6
Nuevo valor para valDos: 7
x: 6 y: 7
x: 216 y: 343
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Observen como omitio la tercer linea, por ende en lugar de tener cinco respuestas tendremos cuatro, en este caso vemos como llamo dos veces la opcion de Cambiar Valores y como efectuo el cuadrado de uno y el cubo de otro. Como ven basicamente es lo mismo la unica diferencia es la utilizacion de un array para almacenar en distintas posiciones otras funciones y las mismas nos da la posibilidad de volverlas a llamar, para nuestro siguiente veremos como pasar de un apuntador a funciones a otras funciones:

static06.cpp

# include <iostream>

using namespace std;

void Cuadrado(int &, int &);
void Cubo(int &, int &);
void Intercambiar(int &, int &);
void ObtenerValores(int &, int &);
void ImprimirValores(void (*)(int &, int &), int &, int &);

int main()
{
 	int valUno = 1, valDos = 2;
 	int opcion;
 	bool fSalir = false;
	void (* apFunc)(int &, int &);
	while(fSalir == false)
 	{
 		cout << "(0)Salir (1)Cambiar Valores ";
		cout << "(2)Cuadrado (3)Cubo (4)Intercambiar: ";
 		cin >> opcion;
		switch(opcion)
 		{
 			case 1:apFunc = ObtenerValores; break;
 			case 2:apFunc = Cuadrado; break;
 			case 3:apFunc = Cubo; break;
 			case 4:apFunc = Intercambiar; break;
 			default:fSalir = true; break;
 		}
 		if (fSalir == true)
 			break;
 		ImprimirValores(apFunc, valUno, valDos);
 	}
 	return 0;
}

void ImprimirValores(void (*apFunc)(int &, int &),int & x, int & y)
{
 	cout << "x: " << x << " y: " << y << endl;
 	apFunc(x, y);
 	cout << "x: " << x << " y: " << y << endl;
}

void Cuadrado(int & rX, int & rY)
{
 	rX *= rX;
 	rY *= rY;
}

void Cubo(int & rX, int & rY)
{
 	int tmp;
	tmp = rX;
 	rX *= rX;
 	rX = rX * tmp;
	tmp = rY;
 	rY *= rY;
 	rY = rY * tmp;
}

void Intercambiar(int & rX, int & rY)
{
 	int temp;
	temp = rX;
	rX = rY;
 	rY = temp;
}

void ObtenerValores(int & rValUno, int & rValDos)
{
 	cout << "Nuevo valor para valUno: ";
 	cin >> rValUno;
 	cout << "Nuevo valor para valDos: ";
 	cin >> rValDos;
}
Anuncios

Este es muy parecido al ejemplo del post anterior porque vuelve el while pero ahora veremos las primeras diferencias, en este caso en los prototipos, aca modificamos a ImprimirValores(), donde aceptara tres elementos, veamos esta linea:

void ImprimirValores(void (*)(int &, int &), int &, int &);
Anuncios

Resalte la parte en negrita porque va a ser en el prototipo donde declaramos el apuntador de las funciones. Observen como es el unico modificado el resto de los prototipos sigue como hicimos siempre. Cuando creamos el apuntador tampoco cambio su expresion porque esta pensado para el resto de las funciones , el ciclo while es exactamente el mismo pero el verdadero cambio viene despues del condicional if donde verifica si debe salir o no, donde nosotros teniamos estas tres lineas:

ImprimirValores(valUno, valDos);
apFunc(valUno, valDos);
ImprimirValores(valUno, valDos);

y ahora la reemplazaremos por esta linea:

ImprimirValores(apFunc, valUno, valDos);
Anuncios

Como se ve, en esta linea pasamos a la funcion el valor del apuntador apFunc obtenido del condicional switch anterior a la funcion Imprimirvalores(), para poder reemplazar estas tres lineas por la linea comentada luego debemos modificar la funcion ImprimirValores(), veamos mas de cerca la funcion antes mencionada:

void ImprimirValores(void (*apFunc)(int &, int &),int & x, int & y)
 {
      cout << "x: " << x << " y: " << y << endl;
      apFunc(x, y);
      cout << "x: " << x << " y: " << y << endl;
 }
Anuncios

En la primer variable volvemos a definir al apuntador para poder recibir al apuntador enviado desde el cuerpo del main(), despues las variables recibidas son las de siempre pero tambien se modifica el cuerpo del mismo, primero imprimiremos los valores de x e y, o valUno y valDos respectivamente, luego llamaremos a la funcion almacenada en el apuntador con los valores enviados a esta funcion y por ultimo volvemos a mostrar las modificaciones realizadas a valUnos y valDos (x e y). El resto de las funciones siguen exactamente igual, la salida es asi:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./static06
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar: 1
x: 1 y: 2
Nuevo valor para valUno: 2
Nuevo valor para valDos: 4
x: 2 y: 4
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar: 2
x: 2 y: 4
x: 4 y: 16
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar: 4
x: 4 y: 16
x: 16 y: 4
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar: 3
x: 16 y: 4
x: 4096 y: 64
(0)Salir (1)Cambiar Valores (2)Cuadrado (3)Cubo (4)Intercambiar: 0
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como se puede ver se obtiene exactamente el mismo resultado, ahora pasaremos a ver como utilizar un typedef con apuntadores a funciones, para el siguiente ejemplo vamos a tomar el codigo anterior y vamos a realizar las siguientes modificaciones.

Primero agregaremos la siguiente linea dentro del bloque de los prototipos:

typedef void (*VAF) (int &, int &);
Anuncios

En este caso utilizamos un typedef para generar un alias para el apuntador a funciones, esto nos ayudara a reemplazar toda la linea que utilizabamos antes, nuestra siguiente modificacion sera cambiar esta linea:

void (* apFunc)(int &, int &);

Por esta otra linea:

VAF apFunc;
Anuncios

Vean como el alias reemplazo a toda la linea donde no es ni necesario declarar a los argumentos de nuestro apuntador porque ya estan contenidos dentro del typedef, nuestra siguiente modificacion sera en la funcion ImprimirValores donde la modificaremos de la siguiente manera:

void ImprimirValores(VAF apFunc,int & x, int & y)
 {
      cout << "x: " << x << " y: " << y << endl;
      apFunc(x, y);
      cout << "x: " << x << " y: " << y << endl;
 }
Anuncios

En este caso reemplazamos toda la llamada al apuntador por nuestro alias generado por medio de typedef y usaremos el mismo nombre de antes para no tener que realizar mas modificaciones en la misma, en este caso el nuevo alias nos permitio dejar de una forma mas practica nuestro codigo sin necesidad de tener que repetir constantemente todo el llamado al apuntador de funciones, si necesitas saber mas sobre typedef te recomiendo este post, veamos como quedo finalmente nuestro codigo:

# include <iostream>

using namespace std;

void Cuadrado(int &, int &);
void Cubo(int &, int &);
void Intercambiar(int &, int &);
void ObtenerValores(int &, int &);
typedef void (*VAF) (int &, int &);
void ImprimirValores(void (*)(int &, int &), int &, int &);

int main()
{
 	int valUno = 1, valDos = 2;
 	int opcion;
 	bool fSalir = false;
	VAF apFunc;
	while(fSalir == false)
 	{
 		cout << "(0)Salir (1)Cambiar Valores ";
		cout << "(2)Cuadrado (3)Cubo (4)Intercambiar: ";
 		cin >> opcion;
		switch(opcion)
 		{
 			case 1:apFunc = ObtenerValores; break;
 			case 2:apFunc = Cuadrado; break;
 			case 3:apFunc = Cubo; break;
 			case 4:apFunc = Intercambiar; break;
 			default:fSalir = true; break;
 		}
 		if (fSalir == true)
 			break;
 		ImprimirValores(apFunc, valUno, valDos);
 	}
 	return 0;
}

void ImprimirValores(VAF apFunc,int & x, int & y)
{
 	cout << "x: " << x << " y: " << y << endl;
 	apFunc(x, y);
 	cout << "x: " << x << " y: " << y << endl;
}

void Cuadrado(int & rX, int & rY)
{
 	rX *= rX;
 	rY *= rY;
}

void Cubo(int & rX, int & rY)
{
 	int tmp;
	tmp = rX;
 	rX *= rX;
 	rX = rX * tmp;
	tmp = rY;
 	rY *= rY;
 	rY = rY * tmp;
}

void Intercambiar(int & rX, int & rY)
{
 	int temp;
	temp = rX;
	rX = rY;
 	rY = temp;
}

void ObtenerValores(int & rValUno, int & rValDos)
{
 	cout << "Nuevo valor para valUno: ";
 	cin >> rValUno;
 	cout << "Nuevo valor para valDos: ";
 	cin >> rValDos;
}
Anuncios

Si lo compilamos y probamos debera funcionar exactamente de la misma manera que el codigo anterior, pasemos a otro ejemplo para ver como usar apuntadores a funciones miembro:

static07.cpp

# include <iostream>

using namespace std;

class Mamifero
{
public:
 	Mamifero():suEdad(1){ }
 	virtual ~Mamifero(){ }
 	virtual void Hablar() const = 0;
 	virtual void Mover() const = 0;
protected:
 	int suEdad;
};

class Perro : public Mamifero
{
public:
 	void Hablar() const { cout << "Guau!\n"; }
 	void Mover() const { cout << "Caminando hacia el amo...\n"; }
};

class Gato : public Mamifero
{
public:
 	void Hablar() const { cout << "Miau!\n"; }
 	void Mover() const { cout << "Caminando sigilosamente...\n"; }
};

class Caballo : public Mamifero
{
public:
 	void Hablar() const { cout << "Yihii!\n"; }
 	void Mover() const { cout << "Galopando...\n"; }
};

int main()
{
 	void (Mamifero::*apFunc)() const = 0;
 	Mamifero *apTr = NULL;
 	int Animal;
 	int Metodo;
 	bool fSalir = false;
	while(fSalir == false)
 	{
 		cout << "(0)Salir (1)Perro (2)Gato (3)Caballo: ";
 		cin >> Animal;
		switch(Animal)
 		{
 			case 1: apTr = new Perro; break;
 			case 2: apTr = new Gato; break;
 			case 3: apTr = new Caballo; break;
 			default: fSalir = true; break;
 		}
 		if (fSalir)
 			break;
		cout << "(1)Hablar (2)Mover: ";
 		cin >> Metodo;
		switch(Metodo)
 		{
 			case 1: apFunc = &Mamifero::Hablar; break;
 			default: apFunc = &Mamifero::Mover; break;
 		}
		(apTr->*apFunc)();
 		delete apTr;
 	}
 	return 0;
}
Anuncios

Para este ejemplo, vamos a utilizar herencia, si lo creen necesario pueden repasarlo en en este post, vamos a crear una clase principal llamada Mamifero, luego tendremos varias clases herederas de estas, estas van a ser Perro, Gato y Caballo, las cuales se van a encargar de redefinir las funciones miembro Hablar() y Mover(), hasta aqui todo como vinimos viendo hasta ahora pero cuando pasamos al cuerpo del main() vemos como la primera linea genera un apuntador de funciones, como los vistos hasta ahora, pero la diferencia radica en la  primera parte donde nos indica la clase maestra y luego genera un apuntador a las funciones miembro de la misma con la mismas expresiones es decir constante y base.

Luego generaremos un apuntador de la clase Mamifero con un valor Null, este sera utilizado para almacenar cual clase heredera usaremos luego, creamos dos variables enteras una de nombre Animal, otra Metodo y el booleano para el bucle while siguiente.

Anuncios

En el while primero nos preguntaran el tipo de animal a elegir, este en base al switch generara en el apuntador apTr un nuevo objeto de las clases herederas, siendo los valores del 1 al 3, de lo contrario sale del programa, fuera de este switch chequea si fSalir es true y sale del programa de lo contrario sigue, en el siguiente chequeo nos pregunta por el metodo, Hablar() o Mover(), en este caso para asignar a apFunc el metodo Hablar() o Mover() de Mamifero segun corresponda. Salido de este condicional en base al objeto creado en apTr llamara al metodo miembro correspondiente almacenado en apFunc, despues de ejecutado procede a eliminarlo y vuelve al principio. La salida del programa es asi:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./static07
(0)Salir (1)Perro (2)Gato (3)Caballo: 1
(1)Hablar (2)Mover: 1
Guau!
(0)Salir (1)Perro (2)Gato (3)Caballo: 2
(1)Hablar (2)Mover: 2
Caminando sigilosamente…
(0)Salir (1)Perro (2)Gato (3)Caballo: 3
(1)Hablar (2)Mover: 1
Yihii!
(0)Salir (1)Perro (2)Gato (3)Caballo: 0
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver el programa siempre buscara las clases herederas dependiendo del objeto creado en apTr si tienen necesidad de comprender un poco mas herencia, repasenlo en este post. Ahora para terminar procederemos a ver nuestro ultimo caso, este va a ser el array de apuntadores a funciones miembro, veamos el ejemplo:

static08.cpp

# include <iostream>

using namespace std;

class Perro
{
public:
 	void Hablar() const { cout << "Guau!\n"; }
 	void Mover() const { cout << "Caminando hacia mi amo...\n"; }
 	void Comer() const { cout << "Devorando la comida...\n"; }
 	void Grunir() const { cout << "Grrrr\n"; }
 	void Gimotear() const { cout << "Sonidos de gimoteos...\n"; }
 	void DarVuelta() const { cout << "Dando vuelta...\n"; }
 	void HacerMuerto() const { cout << "Es el fin de Arturo???\n"; }
};

typedef void (Perro::*AFM)() const;

int main()
{
 	const int MaxFunc = 7;
 	AFM PerroFunciones[MaxFunc] = {
 				&Perro::Hablar,
 				&Perro::Mover,
 				&Perro::Comer,
 				&Perro::Grunir,
 				&Perro::Gimotear,
 				&Perro::DarVuelta,
 				&Perro::HacerMuerto };
	Perro *apPerro = NULL;
 	int metodo;
 	bool fSalir = false;
	while(!fSalir)
 	{
 		cout << "(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir ";
 		cout << "(5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: ";
 		cin >> metodo;
		if (metodo == 0)
 		{
 			fSalir = true;
 		}
 		else
 		{
 			apPerro=new Perro;
 			(apPerro->*PerroFunciones[metodo-1])();
 			delete apPerro;
 		}
 	}
 	return 0;
}
Anuncios

En este codigo, trabajaremos sobre una clase llamada Perro, esta clase va a tener varias funciones miembro, estas van a ser: Hablar(), Mover(), Comer(), Grunir(), Gimotear(), DarVuelta() y HacerMuerto().

Anuncios

Una vez definida cada una de las funciones con las acciones a realizar por nuestro Perro cerramos la clase, luego vamos a crear otro alias con el typedef y empezamos el main(), primero vamos a setear una constante para MaxFunc donde asignara el maximo valor a nuestro array de funciones, en la siguiente linea vamos a crear el array de funciones, el tipo es el nombre del  alias (AFM), creamos el nombre del array y delimitado por MaxFunc, despues iremos agregando todas las funciones miembro de la clase utilizada, luego de definido el array crearemos un apuntador para el objeto de la clase pero ahora lo definiremos como NULL, luego una variable entera llamada metodo y el booleano fSalir. Luego vendra el bucle while, donde le pediremos al usuario el ingreso de la accion de nuestro perro, una vez seleccionada, utiliza un condicional if donde verifica si el valor de metodo es cero, en caso afirmativo setea a fSalir como true y por ende sale del ciclo y el programa, en caso contrario al apuntador le crearemos un nuevo objeto de la clase Perro, luego utilizaremos el apuntador para llamar a la funcion almacenada en el array, y esto es asignado por medio de la variable metodo pero en este caso pueden observar como le restamos uno, esto es para respetar el orden de como se asigna en el array. Luego borramos el apuntador, salimos del condicional y volvemos al principio para tomar otra accion, la salida es asi:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./static08
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 1
Guau!
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 2
Caminando hacia mi amo…
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 3
Devorando la comida…
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 4
Grrrr
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 5
Sonidos de gimoteos…
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 6
Dando vuelta…
(0)Salir (1)Hablar (2)Mover (3)Comer (4)Gruñir (5)Gimotear (6)Dar Vuelta (7)Hacerse el muerto: 0
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver en este caso, se nos facilito como invocar a las funciones miembro por medio de opciones y atraves de un array el ahorrarnos de chequear a traves de un switch y verificar el valor del metodo deseado para ejecutar.

Anuncios

En resumen hoy hemos visto como crear un apuntador a un array de funciones como asignarlo y poder llamarlos en base a su posicion, despues vimos como pasamos un apuntador de funciones a otras funciones, para poder minimizar nuestras acciones en el programa, despues vimos como utilizar un typedef para crear un alias de nuestro apuntadores de funciones, para luego aprender como usar un apuntador para funciones miembro de una clase, o como hemos visto en el ejercicio hicimos una clase base y varias clases herederas, y por ultimo vimos como crear un array para un apuntador de funciones miembro de una clase, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.50

Anuncio publicitario