4.2.1b Modelado de tipos con punteros
§1 Sinopsis
Al tratar con punteros es importante tener muy claro que los punteros señalando a objetos de tipo distinto, son objetos de tipo distinto entre sí. Por ejemplo:
int *pt1; // puntero-a-entero
int const *pt2; // puntero-a-entero constante
En este caso pt1 y pt2 son punteros de distinto tipo (aunque
ambos señalen a valores de tipo int) y por tanto no pueden realizarse asignaciones directas entre ellos. Por ejemplo:
int const peso = 50; // declara peso constante tipo int
int const *pt1; // declara pt1 puntero-a-int-constante
pt1 = &peso; // Ok asignación permitida.
int *pt2; // declara pt2 puntero-a-int
pt2 = &peso; // Error: el puntero no es adecuado
§2 Puntero genérico
Una vez declarado, un puntero permanece encasillado; no puede señalar a objetos de tipo distinto que el original. La excepción,
con ciertas limitaciones ( 4.2.1c
Punteros genéricos) son los punteros declarados inicialmente como puntero-a-void. Por esta razón, este tipo de punteros son
considerados punteros genéricos (no debe ser confundido con puntero nulo
4.2.1).
Ejemplo:
int x = 20; // declara x tipo int
void* pt3; // declara pt3 puntero-a-void (genérico)
pt3 = &x; // Ok asignación permitida
§3 Modelado de punteros
No obstante el "encasillado" antes aludido, el modelado de tipos
( 4.9.9) puede utilizarse también con
punteros, permitiendo reasignarlos [2]. Por ejemplo, siguiendo con el caso anterior, sería posible hacer:
int* pt4;
// declara pt4 puntero-a-int
pt4 = (int*) &peso; // Ok: asignación permitida
Al realizar operaciones con punteros modelados, es
posible que se produzcan corrupciones de memoria o machacamiento de datos, ya que la aritmética de punteros tiene en cuenta el
tamaño del objeto señalado. Ver ejemplo (
4.9.9d)
La asignación entre un puntero-a-tipo1 y un puntero-a-tipo2 sin un moldeado apropiado, puede producir un mensaje de
aviso, o error del compilador, cuando tipo1 y tipo2 son distintos. Si tipo1 es una función y tipo2 no,
o viceversa, la asignación será siempre ilegal. Es decir, los punteros-a-valor no
pueden ser modelados a punteros-a-función (algoritmo) y viceversa. Por otra parte, si tipo1 es un puntero-a-void, el
"casting" no es necesario (con la excepción indicada,
4.2.1d, si tipo2 es un puntero-a-constante).
Ver "Modelado de tipos" (
4.9.9), en especial los operadores dynamic_cast y static_cast para convertir un puntero al
tipo deseado. Adelantemos aquí, que el operador reinterpret:cast permite prácticamente cualquier tipo de conversión, incluso
las mentadas anteriormente entre puntero-a-función y puntero-a-valor. Aunque su uso es extremadamente peligroso y solo debe
utilizarse en circunstancias muy puntuales.
Nota: si te sorprendes a ti mismo necesitando uno de estos modelados, seguramente se debe a alguna de estas dos causas: a.- Eres un virtuoso de la programación C++; b.- Tu análisis es defectuoso, te estás metiendo en una zona de la que no podrás salir fácilmente (estás a punto de volarte la pierna).
[2] Moldeado de tipo "typecasting" en inglés, es el hecho que el compilador trate una expresión de tipo X como si fuese de tipo Y. En lo sucesivo utilizaremos la expresión inglesa (o simplemente "cast") por ser más breve.