Alterações na ordem de inicialização de construtor
A ordem de inicialização para construtores da classe foi alterada de extensões gerenciadas para C++ a Visual C++.
Comparação da ordem de inicialização do construtor
Em extensões gerenciadas para C++, a inicialização do construtor ocorreu na seguinte ordem:
O construtor de classe base, se houver, é invocado.
A lista de inicialização da classe é avaliada.
O corpo do código do construtor de classe é executado.
Essa ordem de execução segue as mesmas convenções que na programação do C++ nativo. O novo idioma do Visual C++ prescreve o seguinte ordem de execução para classes de CLR:
A lista de inicialização da classe é avaliada.
O construtor de classe base, se houver, é invocado.
O corpo do código do construtor de classe é executado.
Observe essa alteração só se aplica às classes de CLR; as classes nativas em Visual C++ ainda seguem as convenções anteriores. Em ambos os casos, estas regras se conectam ao longo de toda a cadeia da hierarquia de uma classe especificada.
Considere o exemplo de código usando extensões gerenciadas para C++:
__gc class A
{
public:
A() : _n(1)
{
}
protected:
int _n;
};
__gc class B : public A
{
public:
B() : _m(_n)
{
}
private:
int _m;
};
Depois da ordem de inicialização do construtor prescrito acima, devemos consulte o seguinte ordem de execução quando novas instâncias da classe B são construídas:
O construtor de classe base A é invocado. O membro de _n é inicializado na 1.
A lista de inicialização da classe B é avaliada. O membro de _m é inicializado na 1.
O corpo do código da classe B é executado.
Agora considere o mesmo código na nova sintaxe do Visual C++:
ref class A
{
public:
A() : _n(1)
{
}
protected:
int _n;
};
ref class B : A
{
public:
B() : _m(_n)
{
}
private:
int _m;
};
A ordem de execução quando novas instâncias da classe B são construídas na nova sintaxe é:
A lista de inicialização da classe B é avaliada. O membro de _m é inicializado na 0 (0 é o valor de não inicializada do membro da classe de _m ).
O construtor de classe base A é invocado. O membro de _n é inicializado na 1.
O corpo do código da classe B é executado.
Observe que uma sintaxe semelhante gerencia resultados diferentes para esses exemplos de código. O construtor de classe B depende de um valor da classe base A para inicializar o membro. Porém, o construtor da classe A ainda não foi chamado. Tal dependência pode ser especialmente perigosa quando a classe herdada depende da memória ou de uma atribuição de recursos para ocorrer no construtor de classe base.
O que isso significa ir de extensões gerenciadas para C++ a Visual C++ 2010
Em muitos casos as alterações à ordem de execução de construtores da classe devem ser transparentes ao programador porque classes base não têm nenhuma ideia de comportamento de classes herdadas. Entretanto, como esses exemplos de código a seguir ilustram, os construtores de classes herdadas extremamente podem ser afetados quando suas listas de inicialização dependem dos valores de membros da classe base. Quando você move o código de extensões gerenciadas para C++ para a nova sintaxe, é recomendável mover tais construções ao corpo do construtor de classe, em que a execução é garantido ocorrer por último.