Operadores de puntero

Operadores de puntero
Información sobre la plantilla
Concepto:Un puntero es una variable cuyo Rvalue es justamente la dirección en memoria de un objeto x
Operadores de puntero. Un puntero es una variable cuyo Rvalue es justamente la dirección en memoria de un objeto x. Es decir: Rvalue(p) == Lvalue(x). Además de los operadores aritméticos, de los que existen versiones para los tipos numéricos y para los punteros, C++ dispone de dos operadores específicos para estos últimos (punteros de cualquier tipo): la indirección * y la referencia &. Además existen dos operadores específicos para punteros-a-clases.

Operador de indirección *

Este operador unitario "deferencia" el operando (que debe ser un puntero). Es decir, devuelve el valor del objeto señalado por el operando. El símbolo * tiene tres usos en C++: operador de multiplicación, indicador de tipo de variable (tipo puntero) y operador de indirección.

Sintaxis

* cast-expresion

Operando cast-expresion debe ser una expresión que se resuelva a un puntero-a-objeto, o a-función. Cuando se usa como operador de indirección se espera que el operando sea una variable de tipo puntero de cualquier tipo (a objeto, o a función). Si el operando es un puntero-a-función, el resultado es un designador de función que puede ser utilizado para invocación de la misma. Si ptr es un puntero-a-X, entonces se cumple que *ptr es el objeto apuntado por ptr y su tipo es el de X. Es decir:

typeid(*ptr) == typeid(X)

Comentario

La expresión n = *ptr; asigna a la variable n el valor del objeto apuntado por ptr y a la inversa: la expresión *ptr = n; asigna al objeto apuntado por ptr el valor de la variable n. Si pt1 y pt2 son dos punteros a las variables v1 y v2, la expresión *pt2 = *pt1; asignaría a la variable apuntada por pt2 el valor de la variable apuntada por pt1, es decir, equivale a v2 = v1;. Los punteros-a-void no pueden ser deferenciados sin un modelado explícito. El resultado de la operación de indirección sobre un puntero es indefinido si se da alguno de los casos siguientes (aquí "indefinido" significa que se obtiene basura o incluso un error irrecuperable):

  • El operando cast-expresion es un puntero nulo. En este caso, lo más probable es que se obtenga un error irrecuperable, como ocurre por ejemplo, con los compiladores Borland C++ 5.5 y MS Visual C++ 6.0 en la situación siguiente:
int x;
int* ptr = 0;
x = *ptr;       // Error!!
  • El operando cast-expresion es un puntero a una variable automática y su bloque ha terminado la ejecución. Ejemplo:

int* iptr;

...
  {
    int x = 0;
    iptr = &x
    ...
  }
...
int z = *iptr;   // Error!!
  • El operando cast-expresion es un puntero a un elemento después del último de una matriz. Ejemplo:
char* nombre = "Bond";
cout << "Letra: " << *nombre << endl;       // Ok.
cout << "Letra: " << *(nombre+5) << endl;   // Error!!

La indirección múltiple

Se ha señalado que los punteros pueden a su vez señalar a punteros. En estos casos, el valor del objeto señalado en el extremo de la cadena de punteros debe obtenerse mediante varias indirecciones. Considere el siguiente ejemplo:

int x = 10;            // entero
int* iptr = &x;        // puntero a entero
int** pptr = &iptr     // puntero a puntero a entero
cout << "Valor x = " << *iptr << endl;
cout << "Valor x = " << **pptr << endl;

Salida:

Valor x = 10
Valor x = 10

La indirección con punteros a función

Hay que resaltar que la indirección de punteros a funciones no se utiliza para obtener la dirección de comienzo del código sino para invocar la función señalada por el puntero y que esta invocación tiene una sintaxis un tanto especial. En efecto, sea el código: void somefunc (...); // una función con sus parámetros ... void (*fptr)(...) = &somefunc; // fptr es puntero a somefunc

En este caso, según la definición de puntero, ocurre que: *fptr == somefunc (ambas expresiones son equivalentes), por lo que en la invocación de la función podemos sustituir el nombre por *fptr, lo que nos conduciría a la notación: *fptr( ...); como fórmula de invocación. Sin embargo, esta expresión debe ser utilizada con paréntesis: (*fptr)( ...);. Se tiene así que las dos sentencias que siguen son igualmente válidas para invocar a la función, pero observe que la segunda tiene una sintaxis especial:

somefunc(...);    // L.1  Ok invocación tradicional
(*fptr)(...);     // L.2  Ok invocación a través de puntero
*fptr(...);       // L.3  Error de sintaxis!!

La indirección de punteros a clases y a miembros

En la programación C/C++ los punteros y sus operaciones constituyen parte fundamental del lenguaje, por lo que es muy frecuente el uso del operador de indirección * para acceder a entidades señaladas por punteros, y desde luego, este operador (herencia del C clásico), cubre suficientemente las necesidades de acceso a través de punteros de cualquier tipo. Sin embargo C++ va un paso más allá cuando se trata de punteros a clases o a sus miembros (también a estructuras y uniones) y ofrece dos operadores adicionales para estos casos.

Operador de indirección de punteros-a-miembro .*

El operador .* de indirección de puntero-a-miembro, es un operador binario cuyo resultado es un objeto-valor (indirección de un puntero-a-propiedad) o un objeto-algoritmo (indirección de un puntero-a-método). Su sintaxis es la siguiente:

<objeto> .* <puntero-a-miembro>
  • <objeto> es la estructura de datos (objeto) en la que se aplicará el desplazamiento ("offset") señalado por el puntero.
  • <puntero-a-miembro> es el puntero que se deferencia

Para que la indirección funcione correctamente, objeto debe ser la instancia de una clase C, mientras que puntero-a-miembro debe ser del tipo X C::*, siendo X el tipo de um miembro de C. Además, el objeto deberá ser accesible desde el puntero. Si el resultado de la indirección es una función (método), solo podrá ser utilizado como operando con el operador de invocación de función ( ). Señalar que el puntero-a-miembro representado por el operador derecho no tiene porqué ser un miembro del objeto señalado por el operador izquierdo (de hecho puede no ser un miembro de clase). En otras palabras, no tiene porqué existir ninguna conexión entre las entidades representadas por ambos operadores.

Operador de referencia &

Este operador unitario es complementario del de indirección. Cuando se aplica a un objeto devuelve la dirección de almacenamiento del objeto (valor que puede ser asignado a un puntero). En C++ el símbolo & se utiliza también como declarador de referencia; casi siempre para pasar argumentos a funciones.

Sintaxis

& cast-expresion

El operando cast-expresion debe ser alguno de los siguientes:

  • Un identificador cualificado. Ejemplo:
  class A {....};
  int A::iptr = &A::miembro_x;
  • El designador de una función. Ejemplo:
  void func() { /* ... */ };  // funcion
  void (*fptr)() = &func;     // Ok. puntero-a-funcion
  • Un Lvalue designando un objeto X que no sea un campo de bits ni tenga un especificador de almacenamiento tipo registro. Recuerde que no es posible obtener la dirección de una variable de registro. Es decir, no se le puede aplicar le operador de referencia a una de estas variables. Tampoco se puede aplicar al valor devuelto por una función, en consecuencia, la expresión x = &func(x); es incorrecta, ya que el valor devuelto por func() es del tipo registro (está en la pila que no es direccionable por este método). Regla: el operador de referencia no puede ser aplicado al valor devuelto por una función.


Véase también

Fuente