Listas de Inicialização do Construtor
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 22 de 104.
Você viu a sintaxe de dois pontos em lições anteriores como Player(std::string n, int h) : name(n), health(h) {}. Isso é chamado de lista de inicialização de membros, e é a maneira preferida de inicializar membros em C++.
A lista de inicialização aparece após a lista de parâmetros do construtor, começando com dois pontos. Cada membro é inicializado diretamente com seu valor, separados por vírgulas:
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) {
// Corpo do construtor (pode estar vazio)
}
};Por que usar listas de inicialização em vez de atribuição no corpo do construtor? Com a atribuição, os membros são primeiro construídos por padrão e, em seguida, recebem novos valores. Com listas de inicialização, os membros são construídos diretamente com os valores corretos — mais eficiente e, às vezes, obrigatório.
Certos membros devem ser inicializados usando a lista:
- membros
const- não podem ser atribuídos após a construção
- Membros de referência - devem ser vinculados na inicialização
- Membros sem construtores padrão
class Player {
const int maxHealth; // Deve usar lista de inicialização
std::string name;
public:
// Isso funciona
Player(int max, std::string n) : maxHealth(max), name(n) {}
// Isso NÃO compilaria:
// Player(int max) { maxHealth = max; } // Erro!
};Os membros são inicializados na ordem em que são declarados na classe, não na ordem da lista de inicialização. Sempre escreva sua lista de inicialização na ordem de declaração para evitar confusão.
Desafio
FácilVamos construir um sistema de configuração para um motor de jogo que demonstra quando e por que as listas de inicialização de membros são essenciais. Você criará uma classe GameConfig com membros que devem ser inicializados usando a sintaxe de lista de inicialização.
Você criará dois arquivos para organizar seu código:
GameConfig.h: Defina uma classeGameConfigque armazena as configurações do jogo. Sua classe deve ter:- Um
const std::string gameName— o título do jogo, que não pode mudar após a criação - Um
const int maxPlayers— a contagem máxima de jogadores, fixa na construção - Um
int& difficultyRef— uma referência a uma configuração de dificuldade externa - Um
int screenWidtheint screenHeight— membros regulares para configurações de exibição - Um construtor que recebe todos os parâmetros necessários e inicializa cada membro usando a lista de inicialização. A lista de inicialização deve seguir a ordem em que os membros são declarados na classe
- Um método
display()que imprime a configuração neste formato:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
- Um
main.cpp: Leia os valores de configuração da entrada e crie um objeto GameConfig. Você precisará:- Ler o nome do jogo (string), máximo de jogadores (int), dificuldade (int), largura (int) e altura (int) da entrada — cada um em uma linha separada
- Criar uma variável local
intpara a dificuldade que a configuração irá referenciar - Criar um objeto
GameConfigusando o construtor com lista de inicialização - Chamar
display()para mostrar a configuração inicial - Modificar a variável de dificuldade diretamente (multiplicá-la por 2)
- Imprimir
"After difficulty change:" - Chamar
display()novamente para mostrar que a referência reflete o valor atualizado
Este desafio destaca por que as listas de inicialização são importantes: seus membros const e o membro de referência não podem ser atribuídos no corpo do construtor — eles devem ser inicializados na lista. O membro de referência também demonstra como as alterações na variável original são refletidas através do objeto de configuração.
Inclua seu arquivo de cabeçalho no main.cpp usando #include "GameConfig.h".
Folha de consulta
Uma lista de inicialização de membros é a maneira preferida de inicializar membros de classe em C++. Ela aparece após a lista de parâmetros do construtor, começando com dois pontos, com cada membro inicializado diretamente:
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {
// Corpo do construtor
}
};Por que usar listas de inicialização? Os membros são construídos diretamente com os valores corretos em vez de serem construídos por padrão e depois atribuídos, tornando o processo mais eficiente.
Necessário para certos membros:
- Membros
const- não podem ser atribuídos após a construção - Membros de referência - devem ser vinculados na inicialização
- Membros sem construtores padrão
class Player {
const int maxHealth;
int& reference;
public:
// Correto - usa lista de inicialização
Player(int max, int& r) : maxHealth(max), reference(r) {}
// Erro - não é possível atribuir const ou referência no corpo
// Player(int max) { maxHealth = max; }
};Importante: Os membros são inicializados na ordem em que são declarados na classe, não na ordem na lista de inicialização. Sempre escreva sua lista de inicialização na ordem de declaração.
Experimente você mesmo
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Ler os 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: Criar um objeto GameConfig usando o construtor de lista de inicialização
// O construtor deve receber: gameName, maxPlayers, difficulty (por referência), width, height
// TODO: Chamar display() para mostrar a configuração inicial
// TODO: Modificar a variável difficulty diretamente (multiplicá-la por 2)
// TODO: Imprimir "After difficulty change:"
// TODO: Chamar display() novamente para mostrar a configuração atualizada
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico