Manejo dinámico de memoria y Polimorfismo (Práctica 4)
Open Source Your Knowledge, Become a Contributor
Technology knowledge has to be shared and made accessible for free. Join the movement.
Punteros en C++
Los punteros (o apuntadores) son variables que se utilizan para almacenar direcciones de memoria, puntualmente las direcciones de memoria que fueron asignadas a variables convencionales en las que se almacenan datos de distinto tipo. Vale la pena entonces recordar que a todas las variables en C++ se les asigna un espacio de memoria en el cual se va almacenar el valor que se le asigne en algún punto de la aplicación a esa variable, el tamaño de dicho espacio va depender del tipo de dato que se pretende almacenar en la variable, del compilador y de la arquitectura del procesador. Cada uno de los espacios de memoria cuenta con una dirección para identificarlo, esta dirección es por lo general un número en representación hexadecimal. Es precisamente ese número correspondiente a la dirección lo que se almacena en un puntero.
Observe la siguiente imagen de ejemplo, se declara una variable var
y se inicializa directamente en la declaración, dicha variable recibe un espacio en memoria para almacenar el valor que se le asigna en la inicialización. Dicho espacio en memoria tiene su propia dirección para poder ser referenciado.
Se puede declarar un puntero para almacenar la dirección de memoria correspondiente a la variable var
, es decir, se puede "apuntar" un puntero a la variable var
. Para declarar un puntero se utiliza la sintaxis para declaración de variables: calificadores opcionales, modificadores opcionales, tipo de dato obligatorio y un identifador para el puntero que también es obligatorio. El tipo de dato del puntero debe ser obligatoriamente el mismo tipo de dato de la variable a la que se pretende apuntar, es decir, si se requiere almacenar la dirección en memoria de una variable de tipo int
, entonces el tipo de dato del puntero también debe ser int
. Un puntero se distingue de otras variables porque en su declaración se utiliza el operador *
luego del tipo de dato y antes del identificador del puntero. Observe a continuación la declaración de varios punteros:
int *puntero_a_int;
float *puntero_a_float;
ClaseA *puntero_a_objeto_claseA;
Para apuntar un puntero a una variable se utilizan el operador de asignación =
, el operador &
y la variable a la que se quiere apuntar. Con el operador &
se obtiene la dirección de la variable y se le asigna al puntero mediante el operador de asignación =
. Observe, ejecute y analice el ejemplo a continuación:
Se puede acceder (leer/modificar) mediante el puntero al valor que está almacenado en la dirección de memoria (la que está almacenada en el puntero por supuesto) utilizando el operador *
. Pruebe el ejemplo a continuación:
Acceso a miembros de clase mediante puntero
Para acceder a los miembros de clase de un objeto a través de un puntero se utiliza el operador flecha ->
en lugar del operador punto .
, obviamente el acceso con operador flecha sigue respetando los niveles de acceso establecidos en la definición de la clase. El siguiente ejemplo ilustra el uso del operador flecha:
Aritmética de punteros
Los punteros almacenan un valor que corresponde a una dirección de memoria y el lenguaje de programación C++ permite que un puntero pueda recibir una nueva dirección de memoria, es decir que sea apuntado a otra variable. Es claro que esto último solo se prodra lograr si la nueva posición de memoria almacena un dato del mismo tipo del puntero o sí se hace una conversión explícita del tipo de dato del puntero. Para poder desplazar un puntero por la memoria C++ permite ejecutar los operadores de adición y sustracción en los punteros, por tanto la dirección que almacena el puntero se puede incrementar o decrementar de acuerdo a la operación que se involucre al puntero. Está permitido el uso de los siguientes operadores: +
, -
, ++
y --
para ejecutar operaciones de aritmética de punteros. Observe el siguiente ejemplo que ilustra el concepto. Puede observar la diferencia entre las direcciones de memoria cada vez que se hace un aumento en la dirección del puntero:
Ejecute y analice el ejemplo a continuación. ¿Puede explicar los incrementos que se hacen al puntero? ¿Por qué se incrementa el puntero en esas cantidades aún sabiendo que los miembros de la estructura están en posiciones contiguas de memoria?
Puntero this
El puntero this
es un miembro privado puntero que tienen de manera implícita todas las clases en C++. Este puntero almacena la dirección de memoria asignada al objeto del cual es miembro. Para una clase X el puntero this
es de tipo X* y solo puede ser invocado por miembros no-estáticos de la clase (recuerde que los miembros estáticos no necesitan de una instancia de clase para ser invocados)
Usos principales del puntero this
:
- Es una práctica generalizada el uso del puntero `this` para referenciar variables de la clase que tienen el mismo nombre de los parámetros de entrada o de variables locales de los métodos de la clase (Con el fin de resolver ambigüedades). Ejemplo:
class MyClass
{
int x, y;
public:
void setX(int x)
{
int y = 25;
this->x = x;
this->y = y;
}
};
class CustomIntStack
{
int array[20];
int cuenta = 0;
public:
CustomIntStack& operator<<(int elem)
{
if(cuenta < 20)
{
array[cuenta] = elem;
cuenta++;
}
else
cout<<"Stack esta lleno!!!"<<endl;
return *this; //En este caso no retorna referencia sino el objeto mismo
}
void printInfo()
{
if(cuenta > 0)
{
for(int i=0; i<cuenta; ++i)
cout<<array[i]<<endl;
}
}
};
int main()
{
CustomIntStack myStack;
myStack<<1<<2<<3<<4<<5<<6<<7; //Agregando elementos al stack
myStack.printInfo();
return 0;
}