Aracılığıyla paylaş


CLR Başvuru Sınıf Nesnesi Bildirimi

Başvuru sınıf türü nesnesini bildirmek ve başlatmak için gereken sözdizimi C++ için Yönetilen Uzantılardan Visual C++ 2010'e değişmiştir.

Yönetilen Uzantılarda, başvuru sınıf türü nesnesi, yıldızın (*) sol tarafına isteğe bağlı __gc anahtar sözcüğü kullanımıyla ISO-C++ işaretçi sözdizimi kullanılarak bildirilirdi. Örneğin, aşağıda Yönetilen Uzantılar sözdizimi altında çeşitli başvuru sınıf türü nesnesi bildirimi vardır:

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);
   }
};

Yeni sözdiziminde, resmi olarak izleme işleyicisi ve daha az resmi olarak şapka denen yeni bildirim belirteci (^) kullanarak başvuru sınıf türü nesnesini bildirirsiniz. (İzleme sıfatı, başvuru türünün CLR yığınında bulunduğu ve bu sebeple yığın sıkıştırma atık toplama sürecinde saydam şekilde yer değiştirebileceği anlamına gelir. İzleme işleyicisi çalışma zamanında saydam olarak güncellenir. İki benzer kavram olan, izleme başvurusu (%) ve iç işaretçi (interior_ptr<>), Değer Türleri Anlamları'te anlatılmıştır.

Bildirim sözdizimini ISO-C++ işaretçi sözdiziminin tekrar kullanılmasından uzaklaştırmanın öncelikli sebepleri şunlardır:

  • İşaretçi sözdizimi kullanımı, başvuru nesnesine aşırı yüklenmiş işleçlerin doğrudan uygulanmasına izin vermez. Bunun yerine, biri işleci iç adını kullanarak çağırmalıydı, örneğin daha sezgisel olan rV1+rV2 yerine rV1->op_Addition(rV2) gibi.

  • Dönüştürme ve işaretçi aritmetiği gibi bir kaç işleme, atık toplanan yığında saklanan nesneler için izin verilmemiştir. İzleme işleyicisi kavramı CLR başvuru türünün doğasını daha iyi yakalar.

İzleme işleyicisinde __gc değiştiricisi gereksizdir ve desteklenmemiştir. Nesnenin kendi kullanımı değişmemiştir; hala üyelere işaretçi üye seçimi işlecinden (->) erişir. Örneğin, aşağıda önceki Yönetilen Uzantılardan yeni sözdizimine çevrilmiş kod örneği vardır:

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);   }
};

CLR Yığınındaki Nesnenin Dinamik Ayırımı

Yönetilen Uzantılarda, yerel ve yönetilen yığın arasında ayırma için iki new ifadesinin varlığı büyük oranda saydamdı. Neredeyse bütün başlatmalarda, derleyici bağlamı kullanarak belleğin yerel yığından mı yoksa yönetilen yığından ayrılacağını belirleyebiliyordu. Örnek:

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

Bağlama göre yığın ayırmayı istemediğinizde, derleyiciyi __gc veya __nogc anahtar sözcükleriyle yönlendirebilirdiniz. Yeni sözdiziminde, iki yeni ifadenin ayrı doğaları gcnew anahtar sözcüğünün sunumuyla açık hale getirildi. Örneğin, önceki üç bildirim yeni sözdiziminde aşağıdaki gibi görünür:

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

Aşağıda önceki bölümde bildirilen Form1 üyelerinin Yönetilen Uzantılar başlatması vardır:

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);
}

Aynı başlatmanın yeni sözdizimine dönüştürülmüş hali buradadır: Başvuru türünün gcnew ifadesinin hedefi olduğunda şapkanın gerekmediğine dikkat ediniz.

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 );
}

Olmayan Nesneye İzleme Başvurusu

Yeni sözdiziminde, 0 artık boş adresi göstermez bunun yerine integer olarak davranılır, 1, 10 veya 100 ile aynı şekilde. İzleme başvurusu için yeni özel bir belirteç boş değeri gösterir. Örneğin, Yönetilen Uzantılarda, olmayan nesne adresine başvuru türünü aşağıdaki gibi başlatırız:

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

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

Yeni sözdiziminde, değer türünün bir Object'e başlatılması veya atanması o veri türünün dolaylı olarak kutulanmasına sebep olur. Yeni sözdiziminde, obj ve obj2'nin ikiside sırasıyla 0 ve 1 değerlerini tutan adresli kutulanmış Int32 nesnesine başlatılır. Örne?in:

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

Bu sebeple, izleme işleyicisinin boş değere açıkça başlatılmasını, atanmasını ve boş değerle kıyaslanmasını gerçekleştirebilmek için yeni anahtar sözcüğü, nullptr, kullanın. Asıl örneğin düzeltilmiş hali aşağıdaki gibidir:

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

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

Bu var olan kod için yeni sözdizimine bağlantı noktası oluşturmayı bir miktar karmaşıklaştırır. Örneğin, aşağıdaki değer sınıf bildirimini düşünün:

__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 [];
};

Burada, hem args hemde env CLR başvuru türüdür. Oluşturucudaki bu iki üyenin 0'a başlatılması yeni sözdizimine geçişte değişmeden kalamaz. Bunun yerine, nullptr'a değiştirilmelidirler:

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;
};

Benzer şekilde, bu üyelere karşı onları 0 ile kıyaslayan sınamalar da üyeleri nullptr ile kıyaslamaya değiştirilmelidir. Bu Yönetilen Uzantılar sözdizimidir:

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;
}

Bu da düzeltilmiş hali, her 0 başlatmasını nullptr ile değiştirerek. Çeviri aracı bu dönüştürmeye, bütün bulunanlar olmasa da NULL makro kullanımını da içeren çoğunu otomatikleştirerek, yardım eder.

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 herhangi bir işaretçiye veya izleme işleyicisine dönüştürülür ancak sayısal bir türe yükseltilmez. Örneğin, aşağıdaki başlatma kümesinde, nullptr sadece ilk ikisi için geçerli bir başlangıç değerdir.

// 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;

Benzer şekilde, aşağıdaki gibi aşırı yüklenmiş yöntem kümesi verilsin:

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

Aşağıdaki gibi nullptr değişmez değeri ile bir çağrı,

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

belirsizdir çünkü nullptr hem izleme işleyicisiyle hem de işaretçiyle eşleşir ve bir türün diğeri üzerine tercihi verilmemiştir. (Bu durum belirsizliği ortadan kaldırmak için açıkça dönüştürmeyi gerektirir.)

0 ile çağrı başlatma (3) ile tam olarak eşleşir:

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

çünkü 0 integer türündedir. f(int) yoksa, çağrı standart dönüştürmelerle f(char*) ile belirsizlik olmadan eşleşir. Eşleşme kuralları tam eşleşmeye standart dönüştürme üzerine öncelik verir. Tam eşleşmenin olmaması durumunda, standart dönüştürmeye değer türünün dolaylı kutulanması üzerine öncelik verilir. Bu belirsizlik olmamasının sebebidir.

Ayrıca bkz.

Başvuru

Classes and Structs (Managed)

^ (Handle to Object on Managed Heap)

nullptr

Kavramlar

Yönetilen Türler (C++/CL)