Punteros y referencias
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 13 de 104.
Ahora que entiendes la memoria stack y heap, exploremos las herramientas que te permiten trabajar directamente con ubicaciones de memoria: punteros y referencias.
Un puntero almacena la dirección de memoria de otra variable. Se declara con * y se obtiene una dirección usando &.
int value = 42;
int* ptr = &value; // ptr contiene la dirección de value
std::cout << ptr; // Imprime la dirección de memoria
std::cout << *ptr; // Desreferencia: imprime 42Una referencia es un alias para una variable existente. Una vez vinculada, siempre se refiere a esa variable. Se declara con &.
int value = 42;
int& ref = value; // ref es un alias para value
ref = 100; // Cambia value a 100
std::cout << value; // Imprime 100Diferencias clave:
| Punteros | Referencias |
|---|---|
| Pueden ser nulos | Deben ser inicializados |
| Pueden ser reasignados | No pueden ser re-vinculados |
Usa * para acceder al valor | Accede al valor directamente |
| Pueden no apuntar a nada | Siempre son válidas |
Ambos son esenciales para pasar objetos a funciones de manera eficiente sin realizar copias, y para trabajar con memoria asignada en el heap. Las referencias son más seguras y sencillas, mientras que los punteros ofrecen más flexibilidad cuando necesitas reasignar o verificar si son null.
Desafío
FácilVamos a construir un sistema simple de manipulación de valores que demuestre cómo los punteros y las referencias funcionan de manera diferente al modificar datos.
Crearás dos archivos para organizar tu código:
ValueOps.h: Define tres funciones que modifican valores enteros de diferentes maneras:doubleByPointer(int* ptr)— toma un puntero y duplica el valor al que apuntatripleByReference(int& ref)— toma una referencia y triplica el valorswapValues(int* a, int* b)— toma dos punteros e intercambia los valores a los que apuntan
main.cpp: Lee dos enteros de la entrada, luego demuestra tanto los punteros como las referencias:- Imprime los valores originales:
"Original: <first> <second>" - Usa
doubleByPointeren el primer valor, luego imprime:"After double: <first>" - Usa
tripleByReferenceen el segundo valor, luego imprime:"After triple: <second>" - Usa
swapValuespara intercambiar ambos valores, luego imprime:"After swap: <first> <second>"
- Imprime los valores originales:
Al llamar a funciones con punteros, recuerda usar el operador de dirección (&) para pasar la dirección de la variable. Las referencias funcionan de manera más natural: simplemente pasa la variable directamente.
Incluye tu archivo de cabecera en main.cpp usando #include "ValueOps.h".
Hoja de referencia
Un puntero almacena la dirección de memoria de otra variable. Se declara con * y se obtiene una dirección usando &:
int value = 42;
int* ptr = &value; // ptr contiene la dirección de value
std::cout << ptr; // Imprime la dirección de memoria
std::cout << *ptr; // Desreferencia: imprime 42Una referencia es un alias para una variable existente. Se declara con &:
int value = 42;
int& ref = value; // ref es un alias para value
ref = 100; // Cambia value a 100
std::cout << value; // Imprime 100Diferencias clave:
| Punteros | Referencias |
|---|---|
| Pueden ser nulos | Deben ser inicializadas |
| Pueden ser reasignados | No pueden ser reasignadas |
Usan * para acceder al valor | Acceden al valor directamente |
| Pueden no apuntar a nada | Siempre son válidas |
Al llamar a funciones con punteros, use el operador de dirección (&) para pasar la dirección de la variable. Las referencias funcionan directamente: simplemente pase la variable.
Pruébalo tú mismo
#include <iostream>
#include "ValueOps.h"
using namespace std;
int main() {
// Lee dos enteros de la entrada
int first, second;
cin >> first;
cin >> second;
// Imprime los valores originales
cout << "Original: " << first << " " << second << endl;
// TODO: Usa doubleByPointer en el primer valor (pasa la dirección usando &)
// TODO: Imprime después de duplicar
// TODO: Usa tripleByReference en el segundo valor (pasa la variable directamente)
// TODO: Imprime después de triplicar
// TODO: Usa swapValues para intercambiar ambos valores (pasa las direcciones usando &)
// TODO: Imprime después del intercambio
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño - Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y Destructores
Constructor por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico