Nasıl yapılır: Sınıfları ve yapıları tanımlama ve kullanma (C++/CLI)

Bu makalede, C++/CLI'da kullanıcı tanımlı başvuru türlerini ve değer türlerini tanımlama ve kullanma işlemi gösterilmektedir.

Nesne örneği oluşturma

Başvuru (başvuru) türleri yığında veya yerel yığında değil, yalnızca yönetilen yığında örneklenebilir. Değer türleri yığında veya yönetilen yığında örneklenebilir.

// mcppv2_ref_class2.cpp
// compile with: /clr
ref class MyClass {
public:
   int i;

   // nested class
   ref class MyClass2 {
   public:
      int i;
   };

   // nested interface
   interface struct MyInterface {
      void f();
   };
};

ref class MyClass2 : public MyClass::MyInterface {
public:
   virtual void f() {
      System::Console::WriteLine("test");
   }
};

public value struct MyStruct {
   void f() {
      System::Console::WriteLine("test");
   }
};

int main() {
   // instantiate ref type on garbage-collected heap
   MyClass ^ p_MyClass = gcnew MyClass;
   p_MyClass -> i = 4;

   // instantiate value type on garbage-collected heap
   MyStruct ^ p_MyStruct = gcnew MyStruct;
   p_MyStruct -> f();

   // instantiate value type on the stack
   MyStruct p_MyStruct2;
   p_MyStruct2.f();

   // instantiate nested ref type on garbage-collected heap
   MyClass::MyClass2 ^ p_MyClass2 = gcnew MyClass::MyClass2;
   p_MyClass2 -> i = 5;
}

Örtük olarak soyut sınıflar

Örtük olarak soyut bir sınıf örneği oluşturulamaz. Bir sınıf, şu durumlarda örtük olarak soyuttur:

  • sınıfının temel türü bir arabirimdir ve
  • sınıfı arabirimin tüm üye işlevlerini uygulamaz.

Bir arabirimden türetilmiş bir sınıftan nesne oluşturamayabilirsiniz. Bunun nedeni, sınıfın örtük olarak soyut olması olabilir. Soyut sınıflar hakkında daha fazla bilgi için bkz . soyut.

Aşağıdaki kod örneği, işlev MyClass::func2 uygulanmadığından sınıfın MyClass örneği oluşturulamadığı gösterir. Örneğin derlenebilmesini sağlamak için açıklamasını kaldırın MyClass::func2.

// mcppv2_ref_class5.cpp
// compile with: /clr
interface struct MyInterface {
   void func1();
   void func2();
};

ref class MyClass : public MyInterface {
public:
   void func1(){}
   // void func2(){}
};

int main() {
   MyClass ^ h_MyClass = gcnew MyClass;   // C2259
                                          // To resolve, uncomment MyClass::func2.
}

Tür görünürlüğü

Ortak dil çalışma zamanı (CLR) türlerinin görünürlüğünü denetleyebilirsiniz. Derlemenize başvurulduğunda, derlemedeki türlerin derleme dışında görünür olup olmadığını denetlersiniz.

public , türü içeren derleme için yönerge içeren herhangi bir kaynak dosyada bir #using türün görünür olduğunu gösterir. private türü içeren derleme için yönerge içeren kaynak dosyalar için bir #using türün görünür olmadığını gösterir. Ancak, özel türler aynı derleme içinde görünür. Varsayılan olarak, sınıfın görünürlüğü şeklindedir private.

Varsayılan olarak Visual Studio 2005'te yerel türlerin derleme dışında genel erişilebilirliği vardı. Özel yerel türlerin nerede yanlış kullanıldığını görmenize yardımcı olması için Derleyici Uyarısı'nı (düzey 1) C4692 etkinleştirin. Değiştiremediğiniz bir kaynak kod dosyasında yerel bir türe genel erişilebilirlik sağlamak için make_public pragması kullanın.

Daha fazla bilgi için bkz . #using Yönergesi.

Aşağıdaki örnekte türleri bildirme ve erişilebilirliğini belirtme ve ardından derleme içinde bu türlere erişme gösterilmektedir. Özel türleri olan bir derlemeye kullanılarak #usingbaşvurulursa, yalnızca derlemedeki genel türler görünür.

// type_visibility.cpp
// compile with: /clr
using namespace System;
// public type, visible inside and outside assembly
public ref struct Public_Class {
   void Test(){Console::WriteLine("in Public_Class");}
};

// private type, visible inside but not outside assembly
private ref struct Private_Class {
   void Test(){Console::WriteLine("in Private_Class");}
};

// default accessibility is private
ref class Private_Class_2 {
public:
   void Test(){Console::WriteLine("in Private_Class_2");}
};

int main() {
   Public_Class ^ a = gcnew Public_Class;
   a->Test();

   Private_Class ^ b = gcnew Private_Class;
   b->Test();

   Private_Class_2 ^ c = gcnew Private_Class_2;
   c->Test();
}

Çıkış

in Public_Class
in Private_Class
in Private_Class_2

Şimdi önceki örneği yeniden yazarak DLL olarak derleyelim.

// type_visibility_2.cpp
// compile with: /clr /LD
using namespace System;
// public type, visible inside and outside the assembly
public ref struct Public_Class {
   void Test(){Console::WriteLine("in Public_Class");}
};

// private type, visible inside but not outside the assembly
private ref struct Private_Class {
   void Test(){Console::WriteLine("in Private_Class");}
};

// by default, accessibility is private
ref class Private_Class_2 {
public:
   void Test(){Console::WriteLine("in Private_Class_2");}
};

Sonraki örnek, derleme dışındaki türlere nasıl erişeceklerini gösterir. Bu örnekte istemci, önceki örnekte yerleşik olarak bulunan bileşeni tüketir.

// type_visibility_3.cpp
// compile with: /clr
#using "type_visibility_2.dll"
int main() {
   Public_Class ^ a = gcnew Public_Class;
   a->Test();

   // private types not accessible outside the assembly
   // Private_Class ^ b = gcnew Private_Class;
   // Private_Class_2 ^ c = gcnew Private_Class_2;
}

Çıkış

in Public_Class

Üye görünürlüğü

, ve erişim tanımlayıcılarının publicprotectedçiftlerini kullanarak bir ortak sınıfın üyesine, derleme dışından erişimden farklı bir derleme içinden erişim sağlayabilirsinizprivate

Bu tablo, çeşitli erişim tanımlayıcılarının etkisini özetler:

Belirleyici Etki
public Üyeye derlemenin içinde ve dışında erişilebilir. Daha fazla bilgi için bkz. public.
private Üyeye hem derleme içinde hem de dışında erişilemez. Daha fazla bilgi için bkz. private.
protected Üyeye derlemenin içinde ve dışından erişilebilir, ancak yalnızca türetilmiş türler için erişilebilir. Daha fazla bilgi için bkz. protected.
internal Üye, derleme içinde genel, derlemenin dışında ise özeldir. internal bağlama duyarlı bir anahtar sözcüktür. Daha fazla bilgi için bkz . Bağlama Duyarlı Anahtar Sözcükler.
public protected -Veya- protected public Üye, derlemenin içinde ortaktır ancak derleme dışında korunur.
private protected -Veya- protected private Üye, derleme içinde korunur, ancak derlemenin dışında özeldir.

Aşağıdaki örnekte, farklı erişim tanımlayıcıları kullanılarak bildirilen üyeleri olan bir genel tür gösterilmektedir. Ardından, derlemenin içinden bu üyelere erişimi gösterir.

// compile with: /clr
using namespace System;
// public type, visible inside and outside the assembly
public ref class Public_Class {
public:
   void Public_Function(){System::Console::WriteLine("in Public_Function");}

private:
   void Private_Function(){System::Console::WriteLine("in Private_Function");}

protected:
   void Protected_Function(){System::Console::WriteLine("in Protected_Function");}

internal:
   void Internal_Function(){System::Console::WriteLine("in Internal_Function");}

protected public:
   void Protected_Public_Function(){System::Console::WriteLine("in Protected_Public_Function");}

public protected:
   void Public_Protected_Function(){System::Console::WriteLine("in Public_Protected_Function");}

private protected:
   void Private_Protected_Function(){System::Console::WriteLine("in Private_Protected_Function");}

protected private:
   void Protected_Private_Function(){System::Console::WriteLine("in Protected_Private_Function");}
};

// a derived type, calls protected functions
ref struct MyClass : public Public_Class {
   void Test() {
      Console::WriteLine("=======================");
      Console::WriteLine("in function of derived class");
      Protected_Function();
      Protected_Private_Function();
      Private_Protected_Function();
      Console::WriteLine("exiting function of derived class");
      Console::WriteLine("=======================");
   }
};

int main() {
   Public_Class ^ a = gcnew Public_Class;
   MyClass ^ b = gcnew MyClass;
   a->Public_Function();
   a->Protected_Public_Function();
   a->Public_Protected_Function();

   // accessible inside but not outside the assembly
   a->Internal_Function();

   // call protected functions
   b->Test();

   // not accessible inside or outside the assembly
   // a->Private_Function();
}

Çıkış

in Public_Function
in Protected_Public_Function
in Public_Protected_Function
in Internal_Function
=======================
in function of derived class
in Protected_Function
in Protected_Private_Function
in Private_Protected_Function
exiting function of derived class
=======================

Şimdi önceki örneği DLL olarak derleyelim.

// compile with: /clr /LD
using namespace System;
// public type, visible inside and outside the assembly
public ref class Public_Class {
public:
   void Public_Function(){System::Console::WriteLine("in Public_Function");}

private:
   void Private_Function(){System::Console::WriteLine("in Private_Function");}

protected:
   void Protected_Function(){System::Console::WriteLine("in Protected_Function");}

internal:
   void Internal_Function(){System::Console::WriteLine("in Internal_Function");}

protected public:
   void Protected_Public_Function(){System::Console::WriteLine("in Protected_Public_Function");}

public protected:
   void Public_Protected_Function(){System::Console::WriteLine("in Public_Protected_Function");}

private protected:
   void Private_Protected_Function(){System::Console::WriteLine("in Private_Protected_Function");}

protected private:
   void Protected_Private_Function(){System::Console::WriteLine("in Protected_Private_Function");}
};

// a derived type, calls protected functions
ref struct MyClass : public Public_Class {
   void Test() {
      Console::WriteLine("=======================");
      Console::WriteLine("in function of derived class");
      Protected_Function();
      Protected_Private_Function();
      Private_Protected_Function();
      Console::WriteLine("exiting function of derived class");
      Console::WriteLine("=======================");
   }
};

Aşağıdaki örnek, önceki örnekte oluşturulan bileşeni tüketir. Üyelerin derleme dışından nasıl erişeceklerini gösterir.

// compile with: /clr
#using "type_member_visibility_2.dll"
using namespace System;
// a derived type, calls protected functions
ref struct MyClass : public Public_Class {
   void Test() {
      Console::WriteLine("=======================");
      Console::WriteLine("in function of derived class");
      Protected_Function();
      Protected_Public_Function();
      Public_Protected_Function();
      Console::WriteLine("exiting function of derived class");
      Console::WriteLine("=======================");
   }
};

int main() {
   Public_Class ^ a = gcnew Public_Class;
   MyClass ^ b = gcnew MyClass;
   a->Public_Function();

   // call protected functions
   b->Test();

   // can't be called outside the assembly
   // a->Private_Function();
   // a->Internal_Function();
   // a->Protected_Private_Function();
   // a->Private_Protected_Function();
}

Çıkış

in Public_Function
=======================
in function of derived class
in Protected_Function
in Protected_Public_Function
in Public_Protected_Function
exiting function of derived class
=======================

Genel ve özel yerel sınıflar

Yönetilen bir türden yerel türe başvurulabilir. Örneğin, yönetilen türdeki bir işlev türü yerel yapı olan bir parametre alabilir. Yönetilen tür ve işlev bir derlemede ortaksa, yerel türün de genel olması gerekir.

// native type
public struct N {
   N(){}
   int i;
};

Ardından, yerel türü kullanan kaynak kod dosyasını oluşturun:

// compile with: /clr /LD
#include "mcppv2_ref_class3.h"
// public managed type
public ref struct R {
   // public function that takes a native type
   void f(N nn) {}
};

Şimdi bir istemci derleyin:

// compile with: /clr
#using "mcppv2_ref_class3.dll"

#include "mcppv2_ref_class3.h"

int main() {
   R ^r = gcnew R;
   N n;
   r->f(n);
}

Statik oluşturucular

Bir CLR türü (örneğin, bir sınıf veya yapı), statik veri üyelerini başlatmak için kullanılabilecek bir statik oluşturucuya sahip olabilir. Statik oluşturucu en çok bir kez çağrılır ve türün herhangi bir statik üyesine ilk kez erişilmeden önce çağrılır.

Örnek oluşturucu her zaman statik bir oluşturucudan sonra çalışır.

Sınıf statik bir oluşturucuya sahipse derleyici, bir oluşturucuya yapılan çağrıyı satır içi olarak çizemez. Sınıf bir değer türüyse, statik bir oluşturucuya sahipse ve bir örnek oluşturucuya sahip değilse, derleyici herhangi bir üye işlevine yönelik çağrıyı satır içi olarak satır içi yapamaz. CLR, çağrıyı satır içi olarak alabilir, ancak derleyici yapamaz.

Statik bir oluşturucuyu özel üye işlevi olarak tanımlayın çünkü yalnızca CLR tarafından çağrılmak üzere tasarlanması gerekir.

Statik oluşturucular hakkında daha fazla bilgi için bkz . Nasıl yapılır: Arabirim Statik Oluşturucu tanımlama (C++/CLI) .

// compile with: /clr
using namespace System;

ref class MyClass {
private:
   static int i = 0;

   static MyClass() {
      Console::WriteLine("in static constructor");
      i = 9;
   }

public:
   static void Test() {
      i++;
      Console::WriteLine(i);
   }
};

int main() {
   MyClass::Test();
   MyClass::Test();
}

Çıkış

in static constructor
10
11

İşaretçinin this semantiği

Türleri tanımlamak için C++\CLI kullanırken, başvuru türündeki this işaretçi tür tutamacındadır. Değer this türündeki işaretçi, iç işaretçi türündedir.

İşaretçinin this bu farklı semantiği, varsayılan dizin oluşturucu çağrıldığında beklenmeyen davranışlara neden olabilir. Sonraki örnek, hem başvuru türünde hem de değer türünde varsayılan dizin oluşturucuya erişmenin doğru yolunu gösterir.

Daha fazla bilgi için bkz . Handle to Object Operator (^) ve interior_ptr (C++/CLI)

// compile with: /clr
using namespace System;

ref struct A {
   property Double default[Double] {
      Double get(Double data) {
         return data*data;
      }
   }

   A() {
      // accessing default indexer
      Console::WriteLine("{0}", this[3.3]);
   }
};

value struct B {
   property Double default[Double] {
      Double get(Double data) {
         return data*data;
      }
   }
   void Test() {
      // accessing default indexer
      Console::WriteLine("{0}", this->default[3.3]);
   }
};

int main() {
   A ^ mya = gcnew A();
   B ^ myb = gcnew B();
   myb->Test();
}

Çıkış

10.89
10.89

İmzaya göre gizle işlevleri

Standart C++ dilinde temel sınıftaki bir işlev, türetilmiş sınıf işlevi aynı türde veya sayıda parametreye sahip olmasa bile türetilmiş bir sınıfta aynı ada sahip bir işlev tarafından gizlenir. Bu adla gizle semantiği olarak bilinir. Bir başvuru türünde, temel sınıftaki bir işlev yalnızca hem ad hem de parametre listesi aynıysa türetilmiş bir sınıftaki bir işlev tarafından gizlenir. İmzaya gizle semantiği olarak bilinir.

Tüm işlevleri meta verilerde olarak işaretlendiğinde sınıf, imzaya göre gizle sınıfı olarak hidebysigkabul edilir. Varsayılan olarak, altında /clr oluşturulan tüm sınıfların işlevleri vardır hidebysig . Bir sınıfın hidebysig işlevleri olduğunda, derleyici doğrudan temel sınıflarda işlevleri ada göre gizlemez, ancak derleyici devralma zincirinde bir ada göre gizle sınıfıyla karşılaşırsa, bu adla gizleme davranışına devam eder.

bir nesnede bir işlev çağrıldığında, imzaya göre gizle semantiği altında, derleyici işlev çağrısını karşılayan bir işlev içeren en türetilmiş sınıfı tanımlar. Sınıfında çağrıyı karşılayan tek bir işlev varsa, derleyici bu işlevi çağırır. Sınıfında çağrıyı karşılayan birden fazla işlev varsa, derleyici hangi işlevin çağrılabileceğini belirlemek için aşırı yükleme çözümleme kurallarını kullanır. Aşırı yükleme kuralları hakkında daha fazla bilgi için bkz . İşlev Aşırı Yüklemesi.

Belirli bir işlev çağrısı için, temel sınıftaki bir işlevin, türetilmiş bir sınıftaki işlevden biraz daha iyi eşleşmesini sağlayan bir imzası olabilir. Ancak, işlev türetilmiş sınıfın bir nesnesinde açıkça çağrıldıysa, türetilmiş sınıftaki işlev çağrılır.

Dönüş değeri işlevin imzasının bir parçası olarak kabul edilmediğinden, aynı ada sahipse temel sınıf işlevi gizlenir ve dönüş değeri türünden farklı olsa bile türetilmiş sınıf işleviyle aynı türde ve sayıda bağımsız değişken alır.

Aşağıdaki örnek, temel sınıftaki bir işlevin türetilmiş bir sınıftaki bir işlev tarafından gizlenmediğini gösterir.

// compile with: /clr
using namespace System;
ref struct Base {
   void Test() {
      Console::WriteLine("Base::Test");
   }
};

ref struct Derived : public Base {
   void Test(int i) {
      Console::WriteLine("Derived::Test");
   }
};

int main() {
   Derived ^ t = gcnew Derived;
   // Test() in the base class will not be hidden
   t->Test();
}

Çıkış

Base::Test

Sonraki örnekte, Microsoft C++ derleyicisinin en çok türetilmiş sınıftaki bir işlevi çağırdığı (bir dönüştürmenin bir veya daha fazla parametreyle eşleşmesi gerekse bile) ve işlev çağrısı için daha iyi bir eşleşme olan bir temel sınıftaki bir işlevi çağırmadığı gösterilmektedir.

// compile with: /clr
using namespace System;
ref struct Base {
   void Test2(Single d) {
      Console::WriteLine("Base::Test2");
   }
};

ref struct Derived : public Base {
   void Test2(Double f) {
      Console::WriteLine("Derived::Test2");
   }
};

int main() {
   Derived ^ t = gcnew Derived;
   // Base::Test2 is a better match, but the compiler
   // calls a function in the derived class if possible
   t->Test2(3.14f);
}

Çıkış

Derived::Test2

Aşağıdaki örnek, temel sınıfın türetilmiş sınıfla aynı imzaya sahip olsa bile bir işlevi gizlemenin mümkün olduğunu gösterir.

// compile with: /clr
using namespace System;
ref struct Base {
   int Test4() {
      Console::WriteLine("Base::Test4");
      return 9;
   }
};

ref struct Derived : public Base {
   char Test4() {
      Console::WriteLine("Derived::Test4");
      return 'a';
   }
};

int main() {
   Derived ^ t = gcnew Derived;

   // Base::Test4 is hidden
   int i = t->Test4();
   Console::WriteLine(i);
}

Çıkış

Derived::Test4
97

Oluşturucuları kopyalama

C++ standardı, bir nesne taşındığında bir kopya oluşturucunun çağrıldığını, böylece bir nesnenin aynı adreste oluşturulup yok edildiğini söyler.

Ancak, MSIL'e derlenmiş bir işlev, bir yerel sınıfın (veya birden çok) değer tarafından geçirildiği ve yerel sınıfın bir kopya oluşturucu veya yıkıcısı olduğu yerel bir işlevi çağırdığında, hiçbir kopya oluşturucu çağrılmaz ve nesne oluşturulduğu konumdan farklı bir adreste yok edilir. Sınıfın kendi içinde bir işaretçisi varsa veya kod nesneleri adrese göre izliyorsa bu davranış sorunlara neden olabilir.

Daha fazla bilgi için bkz . /clr (Ortak Dil Çalışma Zamanı Derlemesi).

Aşağıdaki örnek, bir kopya oluşturucunun ne zaman oluşturulmamış olduğunu gösterir.

// compile with: /clr
#include<stdio.h>

struct S {
   int i;
   static int n;

   S() : i(n++) {
      printf_s("S object %d being constructed, this=%p\n", i, this);
   }

   S(S const& rhs) : i(n++) {
      printf_s("S object %d being copy constructed from S object "
               "%d, this=%p\n", i, rhs.i, this);
   }

   ~S() {
      printf_s("S object %d being destroyed, this=%p\n", i, this);
   }
};

int S::n = 0;

#pragma managed(push,off)
void f(S s1, S s2) {
   printf_s("in function f\n");
}
#pragma managed(pop)

int main() {
   S s;
   S t;
   f(s,t);
}

Çıkış

S object 0 being constructed, this=0018F378
S object 1 being constructed, this=0018F37C
S object 2 being copy constructed from S object 1, this=0018F380
S object 3 being copy constructed from S object 0, this=0018F384
S object 4 being copy constructed from S object 2, this=0018F2E4
S object 2 being destroyed, this=0018F380
S object 5 being copy constructed from S object 3, this=0018F2E0
S object 3 being destroyed, this=0018F384
in function f
S object 5 being destroyed, this=0018F2E0
S object 4 being destroyed, this=0018F2E4
S object 1 being destroyed, this=0018F37C
S object 0 being destroyed, this=0018F378

Yıkıcılar ve sonlandırıcılar

Bir başvuru türündeki yıkıcılar, kaynakların belirleyici bir temizlemesini yapar. Sonlandırıcılar yönetilmeyen kaynakları temizler ve yıkıcı tarafından belirleyici olarak veya atık toplayıcı tarafından belirsiz olarak çağrılabilir. Standart C++ içindeki yıkıcılar hakkında bilgi için bkz . Yıkıcılar.

class classname {
   ~classname() {}   // destructor
   ! classname() {}   // finalizer
};

CLR çöp toplayıcısı kullanılmayan yönetilen nesneleri siler ve artık gerekli olmadığında belleklerini serbest bırakır. Ancak, bir tür çöp toplayıcısının nasıl serbest bırakıldığını bilmediği kaynakları kullanabilir. Bu kaynaklar yönetilmeyen kaynaklar (örneğin yerel dosya tanıtıcıları) olarak bilinir. Yönetilmeyen tüm kaynakları sonlandırıcıda bırakmanızı öneririz. Çöp toplayıcı, yönetilen kaynakları belirsiz bir şekilde serbest bırakır, bu nedenle sonlandırıcıda yönetilen kaynaklara başvurmak güvenli değildir. Bunun nedeni, çöp toplayıcının onları zaten temizlemiş olmasıdır.

Visual C++ sonlandırıcı yöntemiyle Finalize aynı değildir. (CLR belgelerinde sonlandırıcı ve Finalize yöntemi eş anlamlı olarak kullanılır). Finalize yöntemi, bir sınıf devralma zincirindeki her sonlandırıcıyı çağıran çöp toplayıcısı tarafından çağrılır. Visual C++ yıkıcılarından farklı olarak, türetilmiş sınıf sonlandırıcı çağrısı derleyicinin tüm temel sınıflarda sonlandırıcıyı çağırmasına neden olmaz.

Microsoft C++ derleyicisi kaynakların belirleyici sürümünü desteklediğinden veya Finalize yöntemlerini uygulamayı Dispose denemeyin. Ancak bu yöntemleri biliyorsanız visual C++ sonlandırıcısı ve sonlandırıcıyı desene Dispose çağıran bir yıkıcı şöyledir:

// Visual C++ code
ref class T {
   ~T() { this->!T(); }   // destructor calls finalizer
   !T() {}   // finalizer
};

// equivalent to the Dispose pattern
void Dispose(bool disposing) {
   if (disposing) {
      ~T();
   } else {
      !T();
   }
}

Yönetilen bir tür, belirleyici olarak yayınlamayı tercih ettiğiniz yönetilen kaynakları da kullanabilir. Atık toplayıcının, nesne artık gerekli olmadığında belirli bir noktada bir nesneyi belirsiz bir şekilde serbest bırakmasını istemeyebilirsiniz. Kaynakların belirleyici sürümü performansı önemli ölçüde artırabilir.

Microsoft C++ derleyicisi, nesneleri belirlenimci bir şekilde temizlemek için bir yıkıcının tanımını etkinleştirir. Tanımlayıcı olarak serbest bırakmak istediğiniz tüm kaynakları serbest bırakmak için yıkıcıyı kullanın. Bir sonlandırıcı varsa, kod yinelemesini önlemek için yok ediciden çağırın.

// compile with: /clr /c
ref struct A {
   // destructor cleans up all resources
   ~A() {
      // clean up code to release managed resource
      // ...
      // to avoid code duplication,
      // call finalizer to release unmanaged resources
      this->!A();
   }

   // finalizer cleans up unmanaged resources
   // destructor or garbage collector will
   // clean up managed resources
   !A() {
      // clean up code to release unmanaged resources
      // ...
   }
};

Türünüzü kullanan kod yıkıcıyı çağırmazsa, atık toplayıcı sonunda tüm yönetilen kaynakları serbest bırakır.

Yok edicinin varlığı, sonlandırıcının varlığı anlamına gelmez. Ancak sonlandırıcının varlığı, bir yıkıcı tanımlamanız ve sonlandırıcıyı bu yıkıcıdan çağırmanız gerektiğini gösterir. Bu çağrı yönetilmeyen kaynakların belirleyici sürümünü sağlar.

Yıkıcıyı çağırmak nesnenin son haline getirilmesini kullanarak SuppressFinalizegizler. Yıkıcı çağrılmazsa, türünüzün sonlandırıcısı sonunda çöp toplayıcı tarafından çağrılır.

CLR'nin nesneyi belirsiz bir şekilde sonlandırmasına izin vermek yerine nesnenizin kaynaklarını belirleyici bir şekilde temizlemek için yıkıcıyı çağırarak performansı geliştirebilirsiniz.

Visual C++ ile yazılan ve kullanılarak /clr derlenen kod, aşağıdaki durumlarda bir türün yıkıcısını çalıştırır:

Başka bir dilde yazılmış bir istemci türünüzü tüketiyorsa, yıkıcı aşağıdaki gibi çağrılır:

  • çağrısında Dispose.

  • Türüne yapılan bir çağrıda Dispose(void) .

  • C# using deyiminde tür kapsamın dışına çıkarsa.

Başvuru türleri için yığın semantiği kullanmıyorsanız ve yönetilen yığında başvuru türünde bir nesne oluşturuyorsanız, bir özel durumun yıkıcının çalışmasını engellemediğinden emin olmak için try-finally söz dizimini kullanın.

// compile with: /clr
ref struct A {
   ~A() {}
};

int main() {
   A ^ MyA = gcnew A;
   try {
      // use MyA
   }
   finally {
      delete MyA;
   }
}

Türünüzün bir yıkıcısı varsa, derleyici uygulayan IDisposablebir Dispose yöntem oluşturur. Visual C++ dilinde yazılmış ve başka bir dilden tüketilen bir yıkıcısı olan bir tür varsa, bu türe çağrılması IDisposable::Dispose türün yıkıcısının çağrılmasına neden olur. Tür bir Visual C++ istemcisinden kullanıldığında, doğrudan çağıramazsınız Dispose; bunun yerine işlecini kullanarak yıkıcıyı çağırın delete .

Türünüzün sonlandırıcısı varsa, derleyici geçersiz kılan Finalizebir Finalize(void) yöntem oluşturur.

Bir türün sonlandırıcısı veya yıkıcısı varsa, derleyici tasarım desenine göre bir Dispose(bool) yöntem oluşturur. (Bilgi için bkz. Dispose Deseni). Visual C++'da açıkça yazamaz veya çağıramazsınız Dispose(bool) .

Bir tür, tasarım desenine uyan bir temel sınıfa sahipse, türetilmiş sınıfın yıkıcısı çağrıldığında tüm temel sınıfların yıkıcıları çağrılır. (Türünüz Visual C++ dilinde yazılmışsa, derleyici türlerinizin bu deseni uyguladığından emin olur.) Başka bir deyişle, bir başvuru sınıfının yıkıcısı, C++ standardı tarafından belirtilen temellerine ve üyelerine zincirler. İlk olarak, sınıfın yıkıcısı çalıştırılır. Ardından, üyeleri için yıkıcılar, oluşturulduğu sıranın tersinde çalıştırılır. Son olarak, temel sınıfları için yıkıcılar, oluşturulduğu sıranın tersinde çalıştırılır.

Değer türleri veya arabirimler içinde yıkıcılara ve sonlandırıcılara izin verilmez.

Sonlandırıcı yalnızca bir başvuru türünde tanımlanabilir veya bildirilebilir. Oluşturucu ve yıkıcı gibi sonlandırıcının dönüş türü yoktur.

Bir nesnenin sonlandırıcısı çalıştırıldıktan sonra, temel sınıflardaki sonlandırıcılar da en az türetilmiş türle başlayarak çağrılır. Veri üyeleri için sonlandırıcılar, sınıfın sonlandırıcısı tarafından otomatik olarak zincirlenmez.

Sonlandırıcı yönetilen bir türdeki yerel işaretçiyi silerse, yerel işaretçiye veya yerel işaretçi aracılığıyla yapılan başvuruların erken toplanmadığından emin olmanız gerekir. kullanmak KeepAliveyerine yönetilen türde yıkıcıyı çağırın.

Derleme zamanında, bir türün sonlandırıcısı mı yoksa yıkıcısı mı olduğunu algılayabilirsiniz. Daha fazla bilgi için bkz . Tür Özellikleri için Derleyici Desteği.

Sonraki örnekte iki tür gösterilmektedir: biri yönetilmeyen kaynaklara sahip, diğeri ise belirleyici bir şekilde yayımlanan yönetilen kaynaklara sahip.

// compile with: /clr
#include <vcclr.h>
#include <stdio.h>
using namespace System;
using namespace System::IO;

ref class SystemFileWriter {
   FileStream ^ file;
   array<Byte> ^ arr;
   int bufLen;

public:
   SystemFileWriter(String ^ name) : file(File::Open(name, FileMode::Append)),
                                     arr(gcnew array<Byte>(1024)) {}

   void Flush() {
      file->Write(arr, 0, bufLen);
      bufLen = 0;
   }

   ~SystemFileWriter() {
      Flush();
      delete file;
   }
};

ref class CRTFileWriter {
   FILE * file;
   array<Byte> ^ arr;
   int bufLen;

   static FILE * getFile(String ^ n) {
      pin_ptr<const wchar_t> name = PtrToStringChars(n);
      FILE * ret = 0;
      _wfopen_s(&ret, name, L"ab");
      return ret;
   }

public:
   CRTFileWriter(String ^ name) : file(getFile(name)), arr(gcnew array<Byte>(1024) ) {}

   void Flush() {
      pin_ptr<Byte> buf = &arr[0];
      fwrite(buf, 1, bufLen, file);
      bufLen = 0;
   }

   ~CRTFileWriter() {
      this->!CRTFileWriter();
   }

   !CRTFileWriter() {
      Flush();
      fclose(file);
   }
};

int main() {
   SystemFileWriter w("systest.txt");
   CRTFileWriter ^ w2 = gcnew CRTFileWriter("crttest.txt");
}

Ayrıca bkz.

Sınıflar ve yapılar