Construtores Delegados
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 23 de 104.
Quando você tem múltiplos construtores que compartilham uma lógica de inicialização comum, você pode usar construtores delegados para evitar a duplicação de código. Um construtor delegado chama outro construtor da mesma classe em sua lista de inicialização.
class Player {
std::string name;
int health;
int level;
public:
// Construtor primário - faz o trabalho real
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// Delega para o construtor primário
Player(std::string n) : Player(n, 100, 1) {}
// Construtor padrão também delega
Player() : Player("Unknown") {}
};A delegação ocorre na lista de inicializadores usando o nome da classe seguido pelos argumentos. Quando Player() é chamado, ele delega para Player(std::string), que então delega para o construtor de três parâmetros. A cadeia é executada do construtor de destino de volta ao original.
Existe uma regra importante: um construtor delegante não pode ter outros membros em sua lista de inicialização. A delegação deve ser o único item:
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// Erro! Não é possível misturar delegação com inicialização de membros
// Item(int i) : Item(i, 0), id(i) {}
// Correto - apenas delegação
Item(int i) : Item(i, 0) {}
};Construtores delegados ajudam a centralizar a lógica de inicialização em um só lugar, tornando seu código mais fácil de manter e menos propenso a erros decorrentes de código duplicado.
Desafio
FácilVamos construir um sistema de configurações de conexão que demonstra como os construtores delegados podem eliminar a duplicação de código ao encadear chamadas de construtores.
Você criará dois arquivos para organizar seu código:
Connection.h: Defina uma classeConnectionque representa uma conexão de rede com várias opções de configuração. Sua classe deve ter:- Membros privados:
host(string),port(int),timeout(int em segundos) esecure(bool) - Um construtor primário que recebe todos os quatro parâmetros e inicializa todos os membros usando uma lista de inicialização. Este construtor deve imprimir
"Connection configured: <host>:<port>" - Um construtor que recebe apenas
hosteportque delega para o construtor primário comtimeoutpadrão de30esecurepadrão defalse - Um construtor que recebe apenas
hostque delega para o construtor de dois parâmetros comportpadrão de80 - Um construtor padrão que delega para o construtor de um parâmetro com
hostpadrão de"localhost" - Um método
getInfo()que retorna uma string no formato:"<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"
- Membros privados:
main.cpp: Demonstre a cadeia de delegação criando conexões usando diferentes construtores. Leia um nome de host e um número de porta da entrada (cada um em uma linha separada) e, em seguida:- Crie uma
Connectionusando o construtor padrão - Crie uma
Connectionusando apenas o host da entrada - Crie uma
Connectionusando tanto o host quanto a porta da entrada - Crie uma
Connectioncom o host da entrada, a porta da entrada, timeout de60e secure definido comotrue - Imprima
getInfo()para cada conexão, uma por linha
- Crie uma
A cadeia de delegação flui assim: o construtor padrão chama o construtor de um parâmetro, que chama o construtor de dois parâmetros, que chama o construtor primário de quatro parâmetros. Isso significa que a mensagem "Connection configured" é impressa uma vez para cada objeto criado, sempre a partir do construtor primário.
Para o status de segurança em getInfo(), imprima "yes" se secure for true, caso contrário, imprima "no".
Inclua seu arquivo de cabeçalho no main.cpp usando #include "Connection.h".
Folha de consulta
Um construtor delegador chama outro construtor da mesma classe em sua lista de inicialização para evitar a duplicação de código:
class Player {
std::string name;
int health;
int level;
public:
// Construtor primário
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// Delega para o construtor primário
Player(std::string n) : Player(n, 100, 1) {}
// O construtor padrão também delega
Player() : Player("Unknown") {}
};A delegação ocorre na lista de inicialização usando o nome da classe seguido pelos argumentos. Os construtores podem formar uma cadeia de delegação onde um delega para outro.
Regra importante: Um construtor delegador não pode ter outros membros em sua lista de inicialização. A delegação deve ser o único item:
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// Erro! Não é possível misturar delegação com inicialização de membros
// Item(int i) : Item(i, 0), id(i) {}
// Correto - apenas delegação
Item(int i) : Item(i, 0) {}
};Experimente você mesmo
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
// Ler entrada
string host;
int port;
cin >> host;
cin >> port;
// TODO: Criar uma Connection usando o construtor padrão
// TODO: Criar uma Connection usando apenas o host da entrada
// TODO: Criar uma Connection usando tanto o host quanto o port da entrada
// TODO: Criar uma Connection com o host da entrada, port da entrada, timeout=60, secure=true
// TODO: Imprimir getInfo() para cada conexão, uma por linha
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