Sobrepondo e Delegando Construtores

Sobrepondo e delegando construtores

Quando é instanciado um novo objeto, o construtor do objeto é chamado implicitamente pelo compilador C++. Não é incomum ter uma classe com vários construtores que tenham funcionalidades sobreposta. Considere a seguinte classe:

class Foo {
public:
    Foo() {
        // código A...
    }
 
    Foo(int value) {
        // código A...
        // código B...
    }
};

Essa classe tem dois construtores: um construtor padrão e um construtor que recebe um parâmetro inteiro. Como a parte “código A…” do construtor é requerida por ambos os construtores, o código é duplicado em cada construtor.

Obviamente esta é uma má prática que deve ser evitada o máximo possível. Para isso existem algumas maneiras de resolver.

Delegação anterior a versão 11

A solução óbvia seria fazer com que o construtor Foo(int) chamasse o construtor Foo() para fazer a “código A…”. A isto é chamado de Delegação de Construtor. Contudo só está disponível a partir da versão 11 do C++. Vejamos o código abaixo:

class Foo {
public:
    Foo() {
        // código A...
    }
 
    Foo(int value): Foo() { // invoca o contrutor para executar o código A
        // código B...
    }
};

Anteriormente a versão 11 a solução mais utilizada era criar uma função e chamá-la a partir dos dois construtores, representada no código abaixo:

class Foo {
public:
    Foo() {
        Init();
    }
 
    Foo(int value) {
        Init();
        // código B...
    }
 
    void Init() {
        // code to init Foo
    }
};

Delegando construtores no C++ 11

A partir do C++ 11, os construtores passaram a poder chamar outros construtores. Esse processo é chamado de delegação de construtores (ou encadeamento de construtor).

Para que um construtor chame outro, simplesmente deve-se chamar o construtor na lista de inicializadores de membros. Este é um caso em que chamar outro construtor diretamente é aceitável.

Abaixo um segundo exemplo de delegação:

class Empregado {
private:
    int m_id;
    std::string m_name;
 
public:
    Empregado(int id=0, const std::string &name=""):
        m_id(id), m_name(name) {
        std::cout << "Empregado " << m_name << " criado.\n";
    }
 
    // delegando o construtor para não duplicar código
    Empregado(const std::string &name) : Empregado(0, name) { }
};