Deklaracja obiektu klasy odwołania CLR
Składnia deklaruje i tworzy wystąpienia obiektu typu klasy odwołania zmienił się z rozszerzeń zarządzanych języka C++ do Visual C++.
W zarządzanych rozszerzeń obiektu typu klasy odwołania jest zadeklarowana przy użyciu składni wskaźnika ISO C++, z opcjonalnym użyciem __gc słów kluczowych z lewej strony gwiazdy (*).Na przykład Oto odmiany odniesienia deklaracje obiektu typu klasy w sekcji Składnia zarządzane rozszerzenia:
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);
}
};
W obszarze nowe elementy składni, zadeklarować obiektu typu odwołania klasy przy użyciu nowego tokenu deklaracyjne (^) formalnie określone jako śledzenia uchwytu i bardziej nieformalnie jako kapelusz. (Przymiotnik śledzenia oznacza, że typ odwołania znajduje się w stercie CLR i dlatego też przenieść przezroczysty lokalizacji podczas kompaktowania sterty kolekcji garbage.Uchwyt śledzenia przezroczysty jest aktualizowana podczas wykonywania.Są dwa podobne pojęcia Odwołanie śledzenia (%) i wnętrza wskaźnik (interior_ptr<>), który omówiono w Semantyka typów wartości.
Głównych powodów aby przenieść deklaracyjne składni od ponownego użycia składni wskaźnika ISO C++ są następujące:
Stosowanie składni wskaźnika nie pozwalała na przeciążonych operatorów mają być stosowane bezpośrednio do obiektu odwołania.Przeciwnie, trzeba zadzwonić do operatora za pomocą jego nazwy wewnętrzne, takie jak rV1->op_Addition(rV2) zamiast bardziej intuicyjny rV1+rV2.
Liczba operacji kursor, takich jak odlewania i arytmetyki, nie są dozwolone dla obiektów przechowywanych na śmieci zbierane sterty.Pojęcie lepiej uchwyt śledzenia przechwytuje charakter typu CLR odwołania.
__gc Modyfikator na uchwycie śledzenie nie jest konieczne i nie jest obsługiwana.Użycie samego obiektu nie ulega zmianie; nadal dostęp do członków za pomocą wskaźnika Członkowskie selekcji (->).Na przykład Oto poprzednich rozszerzeń zarządzanych przykładowy kod przetłumaczony na nowe elementy składni:
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); }
};
Dynamicznego przydzielania obiektu na stercie CLR
W zarządzanych rozszerzeń istnieniu dwóch new wyrażenia, aby przydzielić między sterty macierzystej i zarządzane było dużym stopniu przezroczyste.W prawie wszystkich przypadkach kompilator jest w stanie ustalić, czy należy przydzielić pamięci ze sterty macierzystej lub zarządzanych za pomocą kontekstu.Na przykład:
Button *button1 = new Button; // OK: managed heap
int *pi1 = new int; // OK: native heap
Int32 *pi2 = new Int32; // OK: managed heap
Gdy nie mają alokację sterty kontekstowych, może skierować kompilator albo __gc lub __nogc słowa kluczowego.W nowych składni oddzielny rodzaj dwóch nowych wyrażeń jest jawnie wraz z wprowadzeniem gcnew słowa kluczowego.Na przykład wcześniejsze deklaracje trzy wyglądać następująco w nowe elementy składni:
Button^ button1 = gcnew Button; // OK: managed heap
int * pi1 = new int; // OK: native heap
Int32^ pi2 = gcnew Int32; // OK: managed heap
W tym miejscu jest zainicjowanie rozszerzenia zarządzane Form1 elementy zadeklarowany w poprzedniej sekcji:
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);
}
Oto inicjalizacji sam przekształcenie na nowe elementy składni.Należy zauważyć, że kapelusz nie jest wymagana dla typu odwołania, gdy jest przedmiotem gcnew wyrażenie.
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 );
}
Odwołanie śledzenia do żadnego obiektu
W nowych składni 0 nie reprezentuje adres null, lecz jest traktowany jako liczba całkowita, taka sama, jak 1, 10, lub 100.Nowy token specjalne reprezentuje wartość null dla odwołania do śledzenia.Na przykład w zarządzanych rozszerzeń, możemy zainicjować typ odwołania, aby rozwiązać żadnego obiektu w następujący sposób:
// OK: we set obj to refer to no object
Object * obj = 0;
// Error: no implicit boxing
Object * obj2 = 1;
Nowe elementy składni, zainicjowanie danych lub przypisanie wartości wpisz do Object powoduje niejawne bokserskie tego typu wartości.W nowych składni zarówno obj i obj2 są inicjowane zająć ramkach obiektów Int32 gospodarstwa wartości 0 i 1, odpowiednio.Na przykład:
// causes the implicit boxing of both 0 and 1
Object ^ obj = 0;
Object ^ obj2 = 1;
W związku z tym, aby wykonać Jawne inicjowanie, przypisania i porównanie uchwytu śledzenia na null, użyj nowego słowa kluczowego, nullptr. Poprawne rewizji oryginalny przykład wygląda następująco:
// OK: we set obj to refer to no object
Object ^ obj = nullptr;
// OK: we initialize obj2 to a Int32^
Object ^ obj2 = 1;
To komplikuje nieco Przenoszenie istniejącego kodu w nowe elementy składni.Na przykład rozważmy następującą deklarację klasy wartość:
__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 [];
};
W tym miejscu zarówno args i env są typy odwołań CLR.Inicjowanie tych dwóch członków, aby 0 w konstruktorze nie ulegają zmianie w przejścia na nowe elementy składni.Przeciwnie, musi zostać zmieniona na 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;
};
Podobnie, uzyskane z tych członków, porównując je do 0 musi również zostać zmieniony aby porównać członków, których nullptr.Oto składnia zarządzane rozszerzenia:
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;
}
Oto rewizji, zastępując każdego 0 wystąpienia z nullptr.Narzędzie służące do tłumaczenia pomaga w tej transformacji dzięki automatyzacji wielu, jeśli nie wszystkie wystąpienia, w tym wykorzystanie NULL makro.
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;
}
nullptr Jest konwertowany na dowolny typ dojścia wskaźnik lub śledzenia, ale nie jest podnoszony do typu całkowitego.Na przykład, w poniższy zbiór inicjalizacji nullptr jest prawidłowy tylko jako wartość początkową do dwóch pierwszych.
// 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;
Podobnie biorąc pod uwagę przeciążone zestaw metod, takich jak następujące:
void f( Object^ ); // (1)
void f( char* ); // (2)
void f( int ); // (3)
Wywołanie z nullptr literału, taki jak poniższy,
// Error: ambiguous: matches (1) and (2)
f( nullptr );
jest niejednoznaczna, ponieważ nullptr pasuje zarówno uchwyt śledzenia i wskaźnik i nie ma żadnych uprzywilejowania nadany do jednego typu nad innymi. (Taka sytuacja wymaga jawne rzutowania w celu odróżnić).
Wywołanie z 0 dokładnie dopasowuje wystąpienie (3):
// OK: matches (3)
f( 0 );
Ponieważ 0 jest typu Integer.Były f(int) nie jest określony, wywołanie jednoznacznie dopasuje się on f(char*) przez standardowe przekształcenie.Reguł dopasowania dać pierwszeństwo dokładny odpowiednik nad standardową konwersją.W przypadku braku dokładne dopasowanie standardową konwersją mają pierwszeństwo nad niejawna bokserskie typu wartości.Dlatego nie ma wątpliwości.
Zobacz też
Informacje
Klasy i strukturach (zarządzanych)
^ (Uchwyt do obiektu na zarządzanego stosu)