Partilhar via


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:

  1. O construtor de classe base, se houver, é invocado.

  2. A lista de inicialização da classe é avaliada.

  3. 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:

  1. A lista de inicialização da classe é avaliada.

  2. O construtor de classe base, se houver, é invocado.

  3. 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:

  1. O construtor de classe base A é invocado. O membro de _n é inicializado na 1.

  2. A lista de inicialização da classe B é avaliada. O membro de _m é inicializado na 1.

  3. 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 é:

  1. 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 ).

  2. O construtor de classe base A é invocado. O membro de _n é inicializado na 1.

  3. 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.

Consulte também

Referência

Construtores (C++)

Inicializadores de construtor

Conceitos

Tipos gerenciados (C++/CL)