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 forma preferida de inicializar membros em C++.
A lista de inicializadores aparece após a lista de parâmetros do construtor, começando com dois-pontos. Cada membro é inicializado diretamente com seu valor, separado 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 com seus valores padrão e, em seguida, recebem novos valores. Com as listas de inicialização, os membros são construídos diretamente com os valores corretos — isso é mais eficiente e, às vezes, obrigatório.
Certos membros devem ser inicializados usando a lista:
- membros
const— não podem receber atribuição 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 inicializadores
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 das declarações para evitar confusão.
Desafio
FácilVamos criar um sistema de configuração para um mecanismo de jogo que demonstra quando e por que as listas de inicializadores de membros são essenciais. Você criará uma classe GameConfig com membros que devem ser inicializados usando a sintaxe de lista de inicializadores.
Você criará dois arquivos para organizar seu código:
GameConfig.h: defina uma classeGameConfigque armazene as configurações do jogo. Sua classe deve ter:- Uma
const std::string gameName: o título do jogo, que não pode ser alterado após a criação - Uma
const int maxPlayers: a quantidade máxima de jogadores, definida na construção - Uma
int& difficultyRef: uma referência a uma configuração de dificuldade externa - Um
int screenWidthe umint screenHeight: membros comuns para as configurações de exibição - Um construtor que receba todos os parâmetros necessários e inicialize cada membro usando a lista de inicializadores. A lista de inicializadores deve seguir a ordem em que os membros são declarados na classe
- Um método
display()que imprima a configuração neste formato:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
- Uma
main.cpp: leia os valores de configuração da entrada e crie um objeto GameConfig. Você precisará:- Ler o nome do jogo (string), o número máximo de jogadores (int), a dificuldade (int), a largura (int) e a altura (int) da entrada: cada um em uma linha separada
- Criar uma variável local
intpara a dificuldade à qual a configuração fará referência - Criar um objeto
GameConfigusando o construtor com lista de inicializadores - Chamar
display()para exibir a configuração inicial - Modificar diretamente a variável de dificuldade (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 inicializadores são importantes: seus membros const e o membro de referência não podem receber atribuições 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 em main.cpp usando #include "GameConfig.h".
Experimente você mesmo
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Ler 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: Crie um objeto GameConfig usando o construtor de lista de inicializadores
// O construtor deve receber: gameName, maxPlayers, difficulty (por referência), width, height
// TODO: Chame display() para mostrar a configuração inicial
// TODO: Modifique a variável difficulty diretamente (multiplique-a por 2)
// TODO: Print "After difficulty change:"
// TODO: Chame 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 POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online