Punteros III

Puntero a funcion

Es posible tomar la direccion de una funcion y asignarla a un puntero. Una funcion tiene una direccion, esta se encuentra dentro del segmento de codigo y marca el comienzo del codigo para esa funcion.
Un puntero a funcion se declara especificando el tipo devuelto y los argumentos aceptados por la funcion a la que apunta, estos dos elementos del puntero deben coincidir con los de la funcion.
La sintaxis para estos punteros es la siguiente:

FUNCION

Type
  devuelto  

Nombre  

(argumento/s)  

Ejemplo:

int

f1

(int,char*);

  PUNTERO A FUNCION   

Type
devuelto

(*Nombre)

(argumento/s)

Ejemplo:

int

(*pf)

(int, char*);

Incializacion de puntero
a funcion
pf = &f1;      (Las dos formas estan
pf = f1;          bien)

La sintaxis de una expresion como:
   int (*pf) (int, char*);
puede resultar poco obvia, a veces es comodo definir un tipo (con typedef) para simplificar las declaraciones. Tambien puede declararse un array de punteros a funcion (todas deben coincidir en tipo devuelto y parametros), un ejemplo de ambos recursos se ve a continuacion:

typedef void (*pmenu) ();
pmenu Archivo [] = {&Abrir, &Guardar, &Cerrar, &Salir};

En primer lugar definimos un tipo, que es un puntero a funciones. Ese tipo nos permite inicializar otros punteros a funciones, en este caso un array de punteros a funciones.

Invocar un puntero a funcion no requiere de desreferenciacion y es muy similar a un llamado comun de funcion. Su sintaxis es:

Nombre_de_funcion (argumento/s);              //Puntero a funcion 
Nombre_de_funcion [indice] (argumento/s);     //Para un array de punteros a funcion

Un puntero a funcion solo puede ser inicializado utilizando la direccion de una funcion, debe existir concordarncia entre funcion y puntero respecto a tipo devuelto y argumentos. Se trata de un puntero especial, no requiere almacenamiento extra de memoria y no esta hecho para itinerar ni para aritmetica de punteros, solo para almacenar la direccion de una funcion, por medio de la cual esta es invocada.

Punteros a objetos

Pueden declararse punteros que apuntan a objetos instancias-de-clase de cierto tipo, la sintaxis a utilizar para la declaracion es la comun, solo es diferente el modo en que es invocado un dato o funcion miembro. Con tal fin se utiliza el operador "->".

Al igual que punteros que apuntan a tipos definidos en el lenguaje, un puntero a objeto, luego de declarado, puede ser inicializado con la direccion de memoria de un objeto conveniente (del mismo tipo), sea de un objeto individual o un array, tambien se lo puede inicializar como puntero nulo o a traves de otro puntero ya inicializado. Sin embargo estas opciones hacen al puntero una entidad dependiente de la memoria que se haya reservado para los objetos que asignan su direccion al puntero. Para que el puntero tenga respaldo independiente en memoria la via indicada es la reserva de memoria dinamica para el mismo.

Si existiera una clase llamada Fecha, una declaracion de puntero a objeto y la reserva de memoria dinamica tendria la forma:

Fecha* hoy;
hoy = new Fecha;

O bien:

Fecha* hoy = new Fecha;

La cantidad de memoria a reservar sera calculada de modo automatico a traves del sizeof de la clase. Ahora bien, el sizeof de una clase no es un valor dinamico, es un valor fijo que queda establecido en tiempo de compilacion y no se modifica, de modo que si miembros de la clase necesitaran memoria dinamica esto deberia implementarse de algun modo en otro sitio, especificamente a traves de un constructor.

El puntero implicito "this"

Cuando una funcion miembro (metodo) es invocada para un objeto, la funcion siempre recibe un parametro extra, no declarado, que es un puntero al objeto que invoco la funcion, ese puntero recibe el nombre generico de "this", y puede ser usado de modo implicito o explicito. Veamos esto detenidamente.

Una clase puede contener miembros 'privados', 'publicos' o 'protegidos', para este tema solo consideraremos los dos primeros. Se trata de especificadores de acceso. Uno de los primeros pasos al manipular clases es la comprobacion de que un dato declarado como 'private' no puede ser accedido de modo normal en el cuerpo de cualquier funcion. Para poder acceder a los datos privados debemos utilizar funciones miembros de la clase donde estan declarados.

Supongamos la siguiente clase:

class num{
int x;
public:
par (){x=0;}
void set () {x=3;}
void set2 (int a) {x=a;}
void set3 (int x) {this->x=x;}
..............
};

Declara varias funciones miembro, se han definido dentro de la clase solo para simplificar la exposicion. La primera se distingue por ser un constructor, pero todas tienen en comun el acceder al dato privado 'x' para darle un valor. No es inmediatamente obvio como es posible para una funcion miembro acceder al dato privado 'x', recordemos el modo en que una funcion cualquiera accede generalmente a datos.

Una funcion comun (no miembro) puede acceder a datos:
-Globales: declarados fuera de toda funcion.
-Locales: declarados dentro de esa funcion.
-Parametros: enviados por otra funcion y que son utilizados directamente (por referencia) o a traves de una copia local (por valor)

En apariencia el dato 'x' no pertenece a ninguna de estas categorias.Cuando declaramos un objeto perteneciente a una clase lo que tenemos es una entidad compuesta de una copia individual de los datos de la clase y de las direcciones de las funciones miembros. Es decir, luego de:

num uno;
num dos;

Existen dos objetos y cada uno tiene su propia 'x'. Esa es la 'x' que aparece en las funciones definidas en esta clase, sera una variable distinta para cada objeto que invoque las funciones (metodos). La cuestion es: ¿como llega ese valor a la funcion, para que esta puede operar con el mismo?
La respuesta es: llega de modo implicito a traves de un puntero a ese objeto, el puntero "this". Tomando como ejemplo la clase definida antes, es como si sus funciones miembro hubieran sido declaradas y definidas de este modo:

void set2 (num* this, int a) {
this->x = a;
}

Solo que el puntero 'this' esta implicito, no es necesario mencionarlo en la lista de parametros y la mayoria de las veces no es necesario mencionarlo en el cuerpo de la funcion tampoco. Se puede acceder a la variable 'x' no porque sea 'global' ni 'local', sino porque llega como parametro, solo que es un parametro especial, implicito.

Vamos a mencionar dos casos, frecuentes, donde es necesario explicitar el puntero "this":
1-Existe ambiguedad respecto a los nombres de variables.
2-Una funcion miembro retorna una referencia al objeto que la invoco.

1-El primer caso se produce si un parametro tiene el mismo nombre que un dato privado, en tal caso la ambiguedad se resuelve utilizando el nombre del parametro, y para poder acceder al dato privado sera necesario explicitar el puntero 'this'. Es lo que sucede en el siguiente caso:

void set3 (int x) {this->x=x;}

Si el parametro tuviera otro nombre ya no seria necesario (aunque tampoco seria un error) explicitar el 'this'. Puede parecer una complicacion innecesaria dar al parametro el mismo nombre que un dato privado, pero se trata de un recurso a veces util para detectar rapidamente, en una funcion de seteo, la relacion entre parametros y datos privados.

2- El segundo caso se produce al retornar una referencia al objeto que invoca la funcion, se trata de un recurso frecuente en la sobrecarga de operadores, pues permite concatenar operaciones, al modo de los operadores '<<' y '>>' en iostream.h. El siguiente ejemplo, simplificado, muestra una posible implementacion:

class complejo {
double x, y;
public:
complejo& operator+= (complejo a){
 x+= a.x;
 y+= a.y;
 return *this;

La funcion retorna una referncia a un "complejo" a traves del puntero 'this'. Los datos 'x' e 'y' del objeto que invoca la funcion no necesitan un 'this' explicito, esto ocurriria en caso de que el parametro fuera, por ej, un entero 'x' o 'y'. La linea final, que explicita el retorno de un puntero al mismo objeto que la invoco, es necesaria para detalles relacionados con la concatenacion de operadores, la modificacion de los datos privados ya se ha hecho en las dos lineas anteriores.


PRINCIPAL

Free Web Hosting