En C++, el modificador const desempeña un papel fundamental dentro de las clases, permitiendo definir miembros inmutables, funciones que no alteran el estado del objeto y objetos constantes. A continuación se describen sus usos más comunes con ejemplos prácticos.
1. Miembros de datos constantes
Un miembro de datos declarado como const debe inicializarse en la lista de inicialización del constructor y no puede modificarse posteriormente.
#include <iostream>
class Contenedor {
public:
Contenedor(int inicial) : dato(inicial) {}
void mostrar() const {
std::cout << "Dato: " << dato << '\n';
}
private:
const int dato;
};
int main() {
Contenedor c(10);
c.mostrar(); // Imprime: Dato: 10
return 0;
}
2. Funciones miembro constantes
Una función marcada como const garantiza que no moidficará ningún miembro no mutable del objeto. Esto permite invocarla desde referencias u objetos constantes.
#include <iostream>
class Registro {
public:
Registro(int v) : valor(v) {}
int obtener() const { return valor; } // No modifica el estado
void actualizar(int v) { valor = v; } // Modifica el estado
private:
int valor;
};
int main() {
Registro r(5);
const Registro& ref_const = r;
std::cout << ref_const.obtener() << '\n'; // Válido
// ref_const.actualizar(20); // Error: función no const en objeto const
}
3. Objetos constantes
Un objeto declarado como const solo permite llamadas a funciones miembro constantes.
#include <iostream>
class Punto {
public:
Punto(int x) : coord(x) {}
int leer() const { return coord; }
private:
int coord;
};
int main() {
const Punto p(7);
std::cout << p.leer() << '\n'; // Correcto
// p.coord = 10; // Error: el objeto es constante
}
4. Parámetros por referencia constante
Al recibir un parámetro como const T&, una función puede aceptar tanto objetos constantes como no constantes sin riesgo de modificarlos.
#include <iostream>
class Medida {
public:
Medida(double v) : magnitud(v) {}
double valor() const { return magnitud; }
private:
double magnitud;
};
void imprimir(const Medida& m) {
std::cout << "Medida: " << m.valor() << '\n';
}
int main() {
Medida a(3.14);
const Medida b(2.71);
imprimir(a); // Objeto no const
imprimir(b); // Objeto const
}
5. Interacción entre funciones const y no const
El compilador distingue entre versiones const y no const de funciones miembro, permitiendo sobrecarga basada en la cualidad const del objeto receptor.
#include <iostream>
class Buffer {
public:
Buffer(char c) : contenido(c) {}
char& acceso() { return contenido; } // Versión modificable
const char& acceso() const { return contenido; } // Versión de solo lectura
private:
char contenido;
};
int main() {
Buffer buf('X');
const Buffer cbuf('Y');
buf.acceso() = 'Z'; // Usa versión no const
std::cout << cbuf.acceso() << '\n'; // Usa versión const
}
El uso correcto de const en clases mejora la seguridad del código al restringir modificaciones no deseadas, facilita la optimización por parte del compilador y comunica claramente las intenciones del diseñador de la clase.