Listas de inicialización del constructor
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy. Lección 22 de 104.
Ya has visto la sintaxis de dos puntos en lecciones anteriores, como Player(std::string n, int h) : name(n), health(h) {}. Esto se llama lista de inicialización de miembros y es la forma preferida de inicializar miembros en C++.
La lista de inicializadores aparece después de la lista de parámetros del constructor, comenzando con dos puntos. Cada miembro se inicializa directamente con su valor, separado por comas:
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// Cuerpo del constructor (puede estar vacío)
}
};¿Por qué usar listas de inicialización en lugar de asignaciones en el cuerpo del constructor? Con las asignaciones, los miembros primero se construyen con sus valores predeterminados y después se les asignan nuevos valores. Con las listas de inicialización, los miembros se construyen directamente con los valores correctos: es más eficiente y, en ocasiones, necesario.
Ciertos miembros deben inicializarse mediante la lista:
- Los miembros de
const- no pueden asignarse después de la construcción
- Los miembros de referencia deben vincularse durante la inicialización
- Miembros sin constructores predeterminados
class Player {
const int maxHealth; // Debe usar lista de inicializadores
std::string name;
public:
// Esto funciona
Player(int max, std::string n) : maxHealth(max), name(n) {}
// Esto NO compilaría:
// Player(int max) { maxHealth = max; } // ¡Error!
};Los miembros se inicializan en el orden en que se declaran en la clase, no en el orden de la lista de inicializadores. Escribe siempre la lista de inicializadores en el orden de declaración para evitar confusiones.
Desafío
FácilConstruyamos un sistema de configuración para un motor de juegos que demuestre cuándo y por qué las listas de inicializadores de miembros son esenciales. Crearás una clase GameConfig con miembros que deben inicializarse usando la sintaxis de la lista de inicializadores.
Crearás dos archivos para organizar tu código:
GameConfig.h: Define una claseGameConfigque almacene la configuración del juego. Tu clase debe tener:- Un
const std::string gameName: el título del juego, que no puede cambiar después de su creación - Un
const int maxPlayers: el número máximo de jugadores, fijado durante la construcción - Un
int& difficultyRef: una referencia a un ajuste de dificultad externo - Un
int screenWidthy unint screenHeight: miembros normales para la configuración de pantalla - Un constructor que acepte todos los parámetros necesarios e inicialice cada miembro usando la lista de inicializadores. La lista de inicializadores debe seguir el orden en que los miembros están declarados en la clase
- Un método
display()que muestre la configuración con este formato:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
- Un
main.cpp: Lee los valores de configuración de la entrada y crea un objeto GameConfig. Deberás:- Leer el nombre del juego (string), el número máximo de jugadores (int), la dificultad (int), el ancho (int) y la altura (int) de la entrada: cada uno en una línea separada
- Crear una variable local
intpara la dificultad a la que hará referencia la configuración - Crear un objeto
GameConfigusando el constructor con lista de inicializadores - Llamar a
display()para mostrar la configuración inicial - Modificar directamente la variable de dificultad (multiplicarla por 2)
- Imprimir
"After difficulty change:" - Llamar a
display()nuevamente para mostrar que la referencia refleja el valor actualizado
Este desafío destaca por qué son importantes las listas de inicializadores: tus miembros const y el miembro de referencia no pueden asignarse en el cuerpo del constructor. Deben inicializarse en la lista. El miembro de referencia también demuestra cómo los cambios en la variable original se reflejan a través del objeto de configuración.
Incluye tu archivo de cabecera en main.cpp usando #include "GameConfig.h".
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Lee los valores de entrada
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: Crea un objeto GameConfig usando el constructor de lista de inicializadores
// El constructor debe recibir: gameName, maxPlayers, difficulty (por referencia), width, height
// TODO: Llama a display() para mostrar la configuración inicial
// TODO: Modifica la variable difficulty directamente (multiplícala por 2)
// TODO: Print "After difficulty change:"
// TODO: Llama a display() de nuevo para mostrar la configuración actualizada
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éricoPractica por tu cuenta: Compilador de C++ online