Construtor chama construtor: cadeias em C++ — é possível?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

"De um construtor para outro": a eterna questão do desenvolvedor C++

\n\n

Imagine a situação: você está escrevendo uma classe com vários construtores. Um aceita três parâmetros, outro dois, outro um. E em todos eles a mesma lógica de inicialização se repete. Dá vontade de escrever algo como MyClass() : MyClass(42, "default") {} — e esquecer a duplicação. Mas o compilador C++ (até certo ponto) olha para isso com desconfiança. É possível chamar um construtor a partir de outro? E se sim — como?

\n\n

Esta pergunta é uma das mais populares no Stack Overflow (dezenas de milhares de visualizações). Não é surpresa: o tópico de cadeias de construtores (constructor chaining) é uma verdadeira pedra no sapato para iniciantes e até mesmo para desenvolvedores experientes que migram para C++ vindos de Java ou Python. Neste artigo, vamos analisar três abordagens para resolver o problema, desde "gambiarras" até soluções elegantes do C++11, e descobrir qual delas vale a pena usar em código real.

\n\n

Por que não podemos simplesmente chamar um construtor de dentro de outro?

\n\n

A abordagem ingênua é assim:

\n\n
class MyClass {\npublic:\n    MyClass() {\n        // algum código\n    }\n    MyClass(int x) {\n        MyClass(); // ERRO: não é permitido!\n    }\n};
\n\n

Em C++, um construtor não é uma função comum. Ele inicializa o objeto uma única vez. Se você tentar chamar explicitamente outro construtor dentro do corpo, o compilador interpretará isso como a criação de um objeto temporário — e nada será inicializado na instância atual. O resultado: ou um erro de compilação, ou (pior) um comportamento indefinido.

\n\n

Antes do padrão C++11, a única maneira legal de "compartilhar" a lógica de inicialização era chamar um método privado init(). Mas isso não era uma delegação real: os membros da classe eram primeiro inicializados pelo construtor padrão e depois sobrescritos. Ineficiente e propenso a bugs.

\n\n

Abordagem nº 1: Construtores delegados (C++11 e posteriores)

\n\n

A partir do C++11, o idioma ganhou um recurso tão esperado — os construtores delegados (delegating constructors). Agora é possível chamar um construtor de dentro de outro diretamente na lista de inicialização:

\n\n
class MyClass {\n    int value;\n    std::string name;\npublic:\n    // Construtor base\n    MyClass(int v, const std::string& n) : value(v), name(n) {\n        std::cout << "Full init: " << value << ", " << name << "\\n";\n    }\n    // Construtor delegado\n    MyClass(int v) : MyClass(v, "default") {}\n    // Outro construtor delegado\n    MyClass() : MyClass(0, "default") {}\n};
\n\n

Como funciona? O construtor MyClass(int v) passa o controle para o construtor MyClass(int, string). Este realiza toda a inicialização, e só então o controle retorna. Regra importante: na lista de inicialização não é permitido misturar a chamada de outro construtor com a inicialização direta de membros. Ou delegação, ou sua própria inicialização — um dos dois.

\n\n

Prós e contras

\n
    \n
  • ✅ Elegância: o código fica limpo, sem duplicação.
  • \n
  • ✅ Desempenho: o objeto é inicializado uma vez, sem operações desnecessárias.
  • \n
  • ⚠️ Limitação: a delegação funciona apenas em uma "profundidade" — a cadeia não pode ser recursiva (você causará um estouro de pilha).
  • \n
  • ⚠️ Compatibilidade: requer C++11 ou superior. Se você estiver preso a um compilador antigo — esta opção não é para você.
  • \n
\n\n

Abordagem nº 2: Método privado init()

\n\n

A maneira clássica "pré-C++11" é extrair a lógica comum para um método privado. Fica assim:

\n\n
class MyClass {\n    int value;\n    std::string name;\n    void init(int v, const std::string& n) {\n        value = v;\n        name = n;\n        std::cout << "Init called\\n";\n                

Blogs

Book Recommendations