Compartilhar via


Declaração de um objeto de classe de referência do CLR

A sintaxe para declarar e criar uma instância de um objeto de um tipo de classe de referência foi alterado de gerenciado Extensions para C++ para Visual C++ 2008.

No gerenciado Extensions, um objeto de tipo de classe de referência é declarado, usando a sintaxe de ponteiro ISO-C++, com um uso opcional do __gc palavra-chave à esquerda (estrela*). Por exemplo, aqui estão várias referência declarações de objeto de tipo de classe sob a sintaxe de gerenciado Extensions:

public __gc class Form1 : public System::Windows::Forms::Form {
private:
   System::ComponentModel::Container __gc *components;
   Button __gc *button1;
   DataGrid __gc *myDataGrid;   
   DataSet __gc *myDataSet;

   void PrintValues( Array* myArr ) {
      System::Collections::IEnumerator* myEnumerator = 
         myArr->GetEnumerator();

      Array *localArray;
      myArr->Copy(myArr, localArray, myArr->Length);
   }
};

Sob a nova sintaxe, declare um objeto de tipo de classe de referência usando um novo token declarativo (^) conhecido formalmente sistema autônomo um alça de acompanhamento e informalmente sistema autônomo um Chapéu.(Adjetivo acompanhamento significa que um tipo de referência fica no heap CLR e pode, portanto, mover de modo transparente locais durante a compactação de heap do lixo coleção.Uma alça de acompanhamento transparente é atualizada durante o tempo de execução.Dois conceitos semelhantes são o referência de acompanhamento (%) e o ponteiro interior (interior_ptr<>), discutido em Semântica de tipo de valor.

O principal resistema autônomoons para mover a sintaxe declarativa longe uma reutilização da sintaxe ISO-C++ ponteiro são sistema autônomo segue:

  • O uso da sintaxe de ponteiro de não permitir que operadores sobrecarregados a ser aplicado diretamente a um objeto de referência.Em vez disso, um tinha chamar o operador usando seu nome interno, sistema autônomo rV1->op_Addition(rV2) em vez de ser mais intuitiva rV1+rV2.

  • Um número de operações de ponteiro, sistema autônomo conversão e aritmética, de ponteiro não permitido para objetos armazenados em um lixo coletado heap.A noção de uma alça de acompanhamento melhor captura a natureza de um tipo de referência do CLR.

The __gc modificador em uma alça de acompanhamento não é necessário e não é suportado. O uso do objeto propriamente dito não é alterado; ele acessa ainda membros com o operador de seleção de membro de ponteiro (->). Por exemplo, eis o exemplo de código anterior gerenciado Extensions traduzido para a nova sintaxe:

public ref class Form1: public System::Windows::Forms::Form {
private:
   System::ComponentModel::Container^ components;
   Button^ button1;
   DataGrid^ myDataGrid;
   DataSet^ myDataSet;

   void PrintValues( Array^ myArr ) {
      System::Collections::IEnumerator^ myEnumerator =
         myArr->GetEnumerator();

      Array ^localArray;
      myArr->Copy(myArr, localArray, myArr->Length);   }
};

Alocação dinâmica de um objeto no heap CLR

No gerenciado Extensions, a existência de dois new expressões para alocar entre a pilha nativa e gerenciada foi amplamente transparente. Em quase todos os casos, o compilador é capaz de usar o contexto para determinar se deve alocar memória do heap nativo ou gerenciado.Por exemplo,

Button *button1 = new Button; // OK: managed heap
int *pi1 = new int;           // OK: native heap
Int32 *pi2 = new Int32;       // OK: managed heap

Quando você não a alocação de heap contextual, você pode direcionar o compilador com ambos os __gc ou __nogc palavra-chave. Na sintaxe de novo, a natureza separada de duas novas expressões é explicitada com a introdução do gcnew palavra-chave. Por exemplo, sistema autônomo declarações anteriores três parecer da seguinte maneira na sintaxe do novo:

Button^ button1 = gcnew Button;        // OK: managed heap
int * pi1 = new int;                   // OK: native heap
Int32^ pi2 = gcnew Int32; // OK: managed heap

Aqui está a inicialização de gerenciado Extensions do Form1 membros declarado na seção anterior:

void InitializeComponent() {
   components = new System::ComponentModel::Container();
   button1 = new System::Windows::Forms::Button();
   myDataGrid = new DataGrid();

   button1->Click += 
      new System::EventHandler(this, &Form1::button1_Click);
}

Esta é a mesma inicialização recast a nova sintaxe.Observe que o chapéu não é necessário para o tipo de referência quando ele é o destino de um gcnew expressão.

void InitializeComponent() {
   components = gcnew System::ComponentModel::Container;
   button1 = gcnew System::Windows::Forms::Button;
   myDataGrid = gcnew DataGrid;

   button1->Click += 
      gcnew System::EventHandler( this, &Form1::button1_Click );
}

Uma referência de acompanhamento a nenhum objeto

Na sintaxe de novo, 0 não representa um endereço nulo, mas é tratado sistema autônomo um inteiro, o mesmo que 1, 10, ou 100. Um novo token especial representa um valor nulo para obter uma referência de acompanhamento.Por exemplo, no gerenciado Extensions, inicializamos um tipo de referência para não tratar nenhum objeto sistema autônomo segue:

// OK: we set obj to refer to no object
Object * obj = 0;

// Error: no implicit boxing
Object * obj2 = 1;

Na nova sintaxe, qualquer inicialização ou atribuição de um tipo de valor para um Object faz com que uma conversão boxing implícita desse tipo de valor. Na sintaxe de novo, ambos os obj e obj2 são inicializados endereçado in a box objetos Int32 mantendo os valores 0 e 1, respectivamente. Por exemplo:

// causes the implicit boxing of both 0 and 1
Object ^ obj = 0;
Object ^ obj2 = 1;

Portanto, para executar a inicialização explícita, atribuição e comparação de uma alça de acompanhamento para nulo, use uma nova palavra-chave, nullptr. A revisão correta do exemplo original fica da seguinte maneira:

// OK: we set obj to refer to no object
Object ^ obj = nullptr;

// OK: we initialize obj2 to a Int32^
Object ^ obj2 = 1;

Isso complica um pouco a portabilidade do código existente para a nova sintaxe.Por exemplo, considere a seguinte declaração de classe de valor:

__value struct Holder {
   Holder( Continuation* c, Sexpr* v ) {
      cont = c;
      value = v;
      args = 0;
      env = 0;
   }

private:
   Continuation* cont;
   Sexpr * value;
   Environment* env;
   Sexpr * args __gc [];
};

Aqui, os dois args e env são tipos de referência do CLR. A inicialização desses dois membros para 0 no construtor não permanecem inalterado na transição para a nova sintaxe. Em vez disso, deve ser alterados para nullptr:

value struct Holder {
   Holder( Continuation^ c, Sexpr^ v )
   {
      cont = c;
      value = v;
      args = nullptr;
      env = nullptr;
   }

private:
   Continuation^ cont;
   Sexpr^ value;
   Environment^ env;
   array<Sexpr^>^ args;
};

Da mesma forma, os testes em relação a esses membros compará-los para 0 também deve ser alterado para comparar os membros nullptr. Aqui está a sintaxe de gerenciado Extensions:

Sexpr * Loop (Sexpr* input) {
   value = 0;
   Holder holder = Interpret(this, input, env);

   while (holder.cont != 0) {
      if (holder.env != 0) {
         holder=Interpret(holder.cont,holder.value,holder.env);
      }
      else if (holder.args != 0) {
         holder = 
         holder.value->closure()->
         apply(holder.cont,holder.args);
      }
   }

   return value;
}

Esta é a revisão, substituindo cada 0 instância com um nullptr. A ferramenta de tradução ajuda a essa transformação automatizando muitos se não usar todas as ocorrências, inclusive o NULL macro.

Sexpr ^ Loop (Sexpr^ input) {
   value = nullptr;
   Holder holder = Interpret(this, input, env);

   while ( holder.cont != nullptr ) {
      if ( holder.env != nullptr ) {
         holder=Interpret(holder.cont,holder.value,holder.env);
      }
      else if (holder.args != nullptr ) {
         holder = 
         holder.value->closure()->
         apply(holder.cont,holder.args);
      }
   }

   return value;
}

The nullptr é convertido em qualquer tipo de identificador de acompanhamento ou o ponteiro, mas não é promovido a um tipo integral. Por exemplo, no seguinte conjunto de inicializações, a nullptr é válida somente sistema autônomo um valor inicial para sistema autônomo dois primeiros.

// OK: we set obj and pstr to refer to no object
Object^ obj = nullptr;
char*   pstr = nullptr; // 0 would also work here

// Error: no conversion of nullptr to 0 …
int ival = nullptr;

Da mesma forma, dado um conjunto sobrecarregado dos métodos, sistema autônomo o seguinte:

void f( Object^ ); // (1)
void f( char* );   // (2)
void f( int );     // (3)

Uma chamada com nullptr literal, sistema autônomo a seguir

// Error: ambiguous: matches (1) and (2)
f(  nullptr );

é ambíguo porque o nullptr corresponde a uma alça de acompanhamento e um ponteiro e não há nenhuma preferência dada a um tipo a Outros. (Essa situação requer uma conversão explícita para disambiguate.)

Uma chamada com 0 corresponde exatamente da instância (3):

// OK: matches (3)
f( 0 );

porque 0 é do tipo inteiro. Foramf(int) não está presente, a telefonar sem ambigüidade corresponderia f(char*) por meio de uma conversão padrão. As regras de correspondência dar prioridade de uma correspondência exata através de uma conversão padrão.Na ausência de uma correspondência exata, uma conversão padrão tem precedência sobre uma conversão boxing implícito de um tipo de valor.É por isso que não há nenhuma ambigüidade.

Consulte também

Conceitos

Tipos gerenciado

Referência

Classes and Estruturas (Gerenciado)

^ (Handle to Objeto on Heap Gerenciado)

nullptr