Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


4.2.1d Puntero genérico

§1 Sinopsis

La declaración: void* vptr;, formalmente: "puntero-a-void", declara que vptr es un puntero genérico, capaz de recibir sin problema el valor de cualquier puntero-a-tipoX (incluso nulo). Significa que pueden apuntar a objetos de cualquier tipo (con las excepciones señaladas ).

Nota: la propia existencia de un puntero de estas características, que podríamos denominar de "manga ancha", y que acepta albergar la dirección de objetos de cualquier tipo, parece ir contra las rigideces en el tratamiento de los tipos de C++ ("Strong type checking" 2.2). Hay que entender que se trata de otro de los legados del C clásico, aceptado por C++ para poder compilar el código de su ancestro.

No confundir un puntero genérico (a void) que aquí se describe, con el puntero nulo ( 4.2.1)

§2 Ejemplo:

int x = 1;
float r = 1.0;
void* vptr = &x;           // puntero-a-void
                           // actualmente señalando a int x
int main () {              // =============
   *(int *) vptr = 2;      // M.1: modifica el valor de x
   vptr = &r;              // actualmente apuntando a float r
   *(float *)vptr = 1.1;   // M.3: modifica el valor de r
}


Observe el "casting" ( 4.9.9) en M.1 y M.3 para que el puntero-a-void pueda ser deferenciado ( 4.9.11a) para acceder a cada tipo de variable. Los punteros-a-void no pueden ser deferenciados sin un modelado explícito, porque el compilador no puede determinar el tamaño del objeto al que referencian (este dato es imprescindible para una mínima aritmética de punteros) [1].

§3 Excepciones

No obstante lo anterior, existen excepciones a la regla de libre asignación a los punteros genéricos.

§3.1 No pueden asignárseles la dirección de una constante. Por ejemplo:

int const x;
void* p = &x;      // Error!

Para una asignación de este tipo es necesario hacer:

void* p = (void*) &x;   // Ok: con un pequeño truco...
void const* p = &x;     // Ok:
int const* p = &x;      // Ok: Esta es la forma canónica


§3.2 Los punteros-a-void tampoco pueden ser asignados a punteros-a-constante. Por ejemplo, siguiendo con el caso anterior:

void* pv;
pv = p;         // Error!

Observe que:

int x = 10;
void* vptr = &x;           // Ok.
int* iptr = vptr;          // L.3: Error!
int* iptr = (int*) vptr;   // L.4: Ok.


La sentencia L.3 produciría un error de compilación: Cannot convert 'void *' to 'int *' in.... La razón es que a pesar de estar actualmente señalando la dirección de un int, para el compilador vptr es todavía un puntero-a-void, por lo que su valor no puede ser asignado a un puntero-a-int. Son tipos diferentes y el compilador indica que él por su cuenta, no puede hacer la conversión necesaria.

En L.4 se permite la asignación porque previamente se ha "disfrazado" el tipo de vptr mediante un modelado adecuado. Forzamos explícitamente al compilador a hacer lo que de "motu proprio" no se ha atrevido.


§3.3 Los punteros-a-función ( 4..2.4) y los punteros-a-miembro ( 4.2.1g) no pueden ser asignados a punteros-a-void.


Ver el operador dynamic_cast ( 4.9.9c) para una discusión sobre la conversión (modelado) de punteros-a-clase en punteros-a-void.

  Inicio.


[1] En determinados casos, el compilador puede realizar una conversión automática de puntero-a-tipoX a puntero-a-void ( 4.4.1a).