Herança em C++: como chamar corretamente o construtor da classe base e não quebrar o código

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

Introdução: por que os construtores das classes pai são um campo minado para iniciantes



Todo mundo que começou a estudar herança em C++, mais cedo ou mais tarde, se deparou com a seguinte situação: você cria uma classe derivada, o compilador reclama, o programa não compila e você não entende o porquê. Na maioria das vezes, a raiz do problema está na chamada incorreta do construtor da classe base. Esta questão no Stack Overflow acumulou milhares de visualizações, e não é à toa: até mesmo desenvolvedores experientes às vezes esquecem regras básicas.



Neste artigo, vamos analisar as regras para chamar o construtor da classe base em C++, passar pelos 5 erros mais comuns e mostrar como evitá-los. Se você quer escrever código confiável sem surpresas — leia até o final.



Breve introdução: como os construtores funcionam na herança



Em C++, os construtores não são herdados. Quando você cria um objeto de uma classe derivada, primeiro o construtor da classe base é chamado (implícita ou explicitamente) e, em seguida, o construtor da classe derivada. Se você não especificar qual construtor da classe pai chamar, o compilador tentará chamar o construtor padrão da classe base. Se ele não existir, você receberá um erro de compilação.



A chamada explícita é feita através da lista de inicialização:



class Base {public:    Base(int x) { /* ... */ }};

class Derived : public Base {public: // Correto: chamada explícita do construtor Base(int) Derived() : Base(42) { /* ... */ }};


Parece simples? Mas é exatamente aqui que os iniciantes cometem 90% dos erros. Vamos analisá-los em ordem.



Top 5 erros ao chamar o construtor da classe base



Erro nº 1: Esqueceu de chamar o construtor da classe pai com parâmetros



O problema mais comum. Se a classe base não tem um construtor padrão e você não o chamou explicitamente — o compilador emitirá um erro.



class Base {public:    Base(int x) { /* inicialização */ }};

class Derived : public Base {public: // ERRO: o compilador tenta chamar Base(), que não existe Derived() { }};


Como corrigir:



class Derived : public Base {public:    // CORRETO: chamamos explicitamente Base(int)    Derived() : Base(0) { }    // Ou passamos o parâmetro externamente:    Derived(int x) : Base(x) { }};


Erro nº 2: Ordem de inicialização incorreta



Muitos pensam que a ordem das chamadas dos construtores na lista de inicialização determina a ordem de execução. Isso não é verdade. A classe base é sempre inicializada primeiro, independentemente de onde você escreveu sua chamada.



class Derived : public Base {private:    int value;public:    // Parece que value é inicializado primeiro? Não!    Derived() : value(10), Base(5) { }    // Na verdade: primeiro Base(5), depois value(10)};


Isso pode levar a erros lógicos se a inicialização de value depender do estado da classe base.



Erro nº 3: Chamar o construtor da classe pai dentro do corpo do construtor



Alguns iniciantes tentam chamar o construtor da classe base dentro das chaves, como um método comum. Isso não funciona — o construtor só pode ser chamado na lista de inicialização.



class Derived : public Base {public:    Derived() {        // ERRO: assim o construtor não é chamado        Base(10); // Apenas cria um objeto temporário e o deleta    }};


Erro nº 4: Confusão com construtores de cópia



Ao implementar o construtor de cópia em uma classe derivada, é necessário chamar explicitamente o construtor de cópia da classe base. Caso contrário, o construtor padrão será chamado e os dados da classe base não serão copiados.



class Derived : public Base {public:    // ERRO: Base será copiado incorretamente    Derived(const Derived& other) { /* ... */ }

// CORRETO: Derived(const Derived&

Blogs

Book Recommendations