Postupy: Definice a používání tříd a struktur (C++/CLI)
Tento článek ukazuje, jak definovat a využívat referenční uživatelem definované typy a typy hodnot v C++/CLI.
Vytvoření instance objektu
Typy odkazů (ref) a typy hodnot může mít vytvořenu instanci pouze na spravované haldě, není v zásobníku nebo na nativní haldě.
// 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;
}
Implicitně abstraktní třídy
Implicitně abstraktní třídy nelze vytvořit instanci.Třída je implicitně abstraktní, pokud je základní typ třídy, rozhraní a třídy neimplementuje všechny členské funkce rozhraní.
Pokud nejste schopni vytvářet objekty z třídy, která je odvozena z rozhraní, může být důvodem, že je implicitně abstraktní třídy.Další informace o abstraktní třídy naleznete v tématu abstraktní.
Následující příklad kódu ukazuje, že MyClass třída nemůže být vytvořena, protože funkce MyClass::func2 není implementována.Chcete-li například ke kompilaci, Odkomentujte 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.
}
Typ viditelnosti
Chcete-li ovládat viditelnost běžné typy language runtime (CLR) tak, že pokud je odkaz na sestavení, typy v sestavení mohou být viditelná nebo není viditelný vně sestavení.
publicoznačuje, že typ je zobrazen zdrojový soubor, který obsahuje #using směrnice pro sestavení, které obsahuje daný typ.privateoznačuje, že typ není viditelná pro zdrojové soubory, které obsahují #using směrnice pro sestavení, které obsahuje daný typ.Privátní typy jsou však viditelné v rámci stejného sestavení.Ve výchozím nastavení, je viditelnost pro třídu private.
Ve výchozím nastavení před Visual C++ 2005 kdyby nativní typy veřejnou přístupnost mimo sestavení.Povolit C4692 (úroveň 1) upozornění kompilátoru které vám pomůže objasnit, kde soukromé nativní typy jsou používány nesprávně.Použití make_public pragma přidělit veřejnou přístupnost nativního typu v soubor zdrojového kódu, který nelze změnit.
Další informace naleznete v tématu # použití směrnice (C++).
Následující příklad ukazuje, jak deklarovat typy a určit jejich přístupnost a poté získat přístup k tyto typy uvnitř sestavení.Samozřejmě, pokud je odkaz na sestavení, které má soukromý typy pomocí #using, pouze veřejné typy v sestavení jsou viditelné.
// 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();
}
Výsledek
Nyní můžeme přepsat předchozí ukázka tak, že je vytvořena jako knihovny DLL.
// 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");}
};
Další příklad ukazuje, jak získat přístup k typy mimo sestavení.V této ukázce klient využívá součást, která je integrována v předchozí ukázce.
// 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;
}
Výsledek
Člen viditelnost
Můžete provést přístup členem veřejné třídy z v rámci stejného sestavení liší od přístupu k ní z mimo sestavení pomocí dvojice specifikátory přístupu public, protected, aprivate
Tato tabulka shrnuje vliv různých specifikátory přístupu:
Specifikátor |
Účinek |
---|---|
|
Člen je přístupný uvnitř i vně sestavení.Další informace naleznete v tématu veřejné (C++). |
|
Člen není přístupný, ani mimo sestavení.Další informace naleznete v tématu soukromé (C++). |
|
Člen je přístupný uvnitř a vně sestavení, ale pouze pro odvozené typy.Další informace naleznete v tématu chráněné (C++). |
|
Člen je veřejnosti uvnitř sestavení, ale soukromé mimo sestavení.internalje kontextové klíčové slovo.Další informace naleznete v tématu Kontextově závislá klíčová slova (rozšíření komponent C++). |
|
Člen je veřejnosti uvnitř sestavení, ale chráněné mimo sestavení. |
|
Člen je chráněný uvnitř sestavení, ale soukromé mimo sestavení. |
Následující ukázka zobrazuje veřejné typ, který má členy, které jsou deklarovány pomocí různých přístupnosti a potom zobrazí přístup k těm členům z uvnitř sestavení.
// type_member_visibility.cpp
// 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();
}
Výsledek
Nyní můžeme sestavit předchozí ukázka jako knihovna DLL.
// type_member_visibility_2.cpp
// 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("=======================");
}
};
Následující příklad využívá součást, která je vytvořena v předchozí ukázce a tím ukazuje, jak přistupovat k členům z mimo sestavení.
// type_member_visibility_3.cpp
// 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();
}
Výsledek
Veřejné a soukromé nativních tříd
Nativní typ můžete odkazovat z spravovaného typu.Funkce v spravovaného typu může trvat parametr, jehož typ je nativní struktury.Pokud jsou v sestavení spravovaného typu a funkce, pak nativního typu musí být také veřejné.
// mcppv2_ref_class3.h
// native type
public struct N {
N(){}
int i;
};
Dále vytvořte soubor zdrojového kódu, který využívá nativní typ:
// mcppv2_ref_class3.cpp
// 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) {}
};
Nyní kompilace klienta:
// mcppv2_ref_class4.cpp
// compile with: /clr
#using "mcppv2_ref_class3.dll"
#include "mcppv2_ref_class3.h"
int main() {
R ^r = gcnew R;
N n;
r->f(n);
}
Statické konstruktory
Typ CLR – například třída nebo struktura – může obsahovat statický konstruktor, který slouží k inicializaci statické datové členy.Statický konstruktor se nazývá maximálně jednou a se nazývá statický člen typu se před přístupem k první.
Konstruktoru instance se spouští vždy po statického konstruktoru.
Kompilátor nemůže vložené volání konstruktoru třídy má statického konstruktoru.Kompilátor nemůže vložené volání jakékoli členské funkce třídy je hodnotový typ, obsahuje statický konstruktor a nemá konstruktoru instance.Modul CLR může vložené volání, ale kompilátor nemůže.
Definujte statický konstruktor jako soukromý člen funkce, protože je určen má být volána pouze modulem CLR.
Další informace o statické konstruktory, viz Postupy: Definice a používání statického konstruktoru (C++/CLI) .
// mcppv2_ref_class6.cpp
// 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();
}
Výsledek
Sémantika tohoto ukazatele
Pokud používáte Visual C++ k definování typů, this je ukazatel v typu odkazu typu "zpracování".this Je ukazatel typu hodnoty typu "vnitřní ukazatel".
Tyto různé sémantiku this ukazatel může způsobit neočekávané chování, když je zavolána výchozí indexeru.Následující příklad ukazuje správný způsob přístupu k indexeru výchozí typ odkazu a typu hodnoty.
Další informace naleznete v tématu
// semantics_of_this_pointer.cpp
// 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();
}
Výsledek
Funkce skrýt podpisů
Standard C++ funkce v základní třídě je skryta ve funkci, která má stejný název v odvozené třídě, i v případě, že stejné číslo nebo druh parametry nemá funkce odvozené třídy.To se označuje jako Skrýt podle názvu sémantiku.V typu odkazu můžete funkci základní třídy pouze skryté pomocí funkce v odvozené třídě je-li název a seznam parametrů jsou stejné.To se nazývá Skrýt podpis sémantiku.
Třída je považováno za třídu skrýt pomocí podpisu, pokud všechny jeho funkce jsou označeny v metadatech jako hidebysig.Ve výchozím nastavení jsou všechny třídy, které jsou vytvářeny pod /clr mít hidebysig funkce.Avšak třídy, který je zkompilován s použitím /clr:oldSyntax nemá hidebysig funkce; Namísto toho jsou funkce skrýt podle názvu.Pokud má třída hidebysig funkce, kompilátor neskryje funkcí podle názvu v jakékoli přímé základní třídy, ale pokud kompilátor narazí skrýt podle názvu třídy v řetězce dědičnosti, pokračuje toto chování skrýt podle názvu.
Pod sémantiku skrýt podpisů při volání funkce objektu, kompilátor identifikuje nejvíce odvozené třídy, která obsahuje funkci, která by mohla splňovat volání funkce.Pokud je třída, která může uspokojit volání pouze jednu funkci, kompilátor volání této funkce.Pokud je třída, která může uspokojit volání více než jednu funkci, kompilátor používá přetížení rozlišení pravidel, která určují funkce volání.Další informace o pravidlech přetížení, viz Funkce přetížení.
Pro volání dané funkce funkce základní třídy mít podpis, který usnadňuje mírně lepší shodu než funkci v odvozené třídě.Avšak pokud funkce byla volána explicitně na objekt odvozené třídy, je volána funkce v odvozené třídě.
Protože vrácená hodnota není považován za součást podpisu na funkci, funkci základní třídy je skryta v případě má stejný název a má stejný počet a druh argumenty jako funkce odvozené třídy, i v případě, že se liší v typ vrácené hodnoty.
Následující příklad ukazuje, že funkce v základní třídě není skryté pomocí funkce v odvozené třídě.
// hide_by_signature_1.cpp
// 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();
}
Výsledek
Následující příklad ukazuje, že kompilátor Visual C++ volá funkci v Většina odvozených tříd – i v případě, že tak, aby odpovídal jeden nebo více parametrů je vyžadován převod – a zavolá funkci základní třídy, která je lepší shoda pro volání funkce.
// hide_by_signature_2.cpp
// 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);
}
Výsledek
Následující příklad ukazuje, že je možné skrýt funkce i v případě, že základní třída má stejnou signaturu jako odvozené třídy.
// hide_by_signature_3.cpp
// 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);
}
Výsledek
Následující příklad definuje komponent, který je zkompilován s použitím /clr:oldSyntax.Třídy, které jsou definovány pomocí spravovaných rozšíření jazyka C++ nutné skrýt podle názvu členské funkce.
// hide_by_signature_4.cpp
// compile with: /clr:oldSyntax /LD
using namespace System;
public __gc struct Base0 {
void Test() {
Console::WriteLine("in Base0::Test");
}
};
public __gc struct Base1 : public Base0 {
void Test(int i) {
Console::WriteLine("in Base1::Test");
}
};
Další ukázka spotřebovává komponenty, která je integrována v předchozí ukázce.Oznámení jak skrýt pomocí podpis funkce není u základních tříd typy, které jsou kompilovány pomocí /clr:oldSyntax.
// hide_by_signature_5.cpp
// compile with: /clr:oldSyntax /LD
// compile with: /clr
using namespace System;
#using "hide_by_signature_4.dll"
ref struct Derived : public Base1 {
void Test(int i, int j) {
Console::WriteLine("Derived::Test");
}
};
int main() {
Derived ^ t = gcnew Derived;
t->Test(8, 8); // OK
t->Test(8); // OK
t->Test(); // C2661
}
Kopírovat konstruktory
C++ standard říká, že kopie konstruktoru je volána, když přesunete objekt, tak, že objekt je vytvořen a zničeny na stejné adrese.
Nicméně, když /clr slouží ke kompilaci a funkce, která je zkompilována pro jazyk MSIL volání nativní funkce, pokud nativní třídy – nebo více než jeden – je předán podle hodnoty a kde nativní třídy má kopie konstruktoru a destruktoru, se nazývá žádné kopie konstruktoru a objekt je zničeno na jinou adresu, než ve které byl vytvořen.To může způsobit potíže, pokud má třída ukazatel do sebe nebo kód je sledování objektů podle adresy.
Další informace naleznete v tématu /CLR (kompilace společné Language Runtime).
Následující ukázka znázorňuje, kdy není vytvořena kopie konstruktoru.
// breaking_change_no_copy_ctor.cpp
// 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);
}
Výsledek
Destruktory a finalizačních metod
Destruktory v typu odkazu provádět deterministický vyčištění prostředků.Finalizační metody čištění nespravovaných prostředků a můžete volat deterministically destruktoru nebo nedeterministicky uvolňování.Informace o destruktory ve standardní C++ naleznete v tématu Destruktory (C++).
class classname {
~classname() {} // destructor
! classname() {} // finalizer
};
Chování destruktory ve spravované třídy Visual C++ se liší od spravovaných rozšíření jazyka C++.Další informace o těchto změnách naleznete v tématu Sémantické změmy v destruktoru.
Uvolňování paměti modulu CLR Odstraní nepoužívané spravované objekty a uvolní jejich paměť, pokud již nejsou zapotřebí.Typ však mohou využívat prostředky, které uvolňování neví, jak uvolnit.Tyto prostředky jsou známé jako nespravované prostředky (nativní soubor zpracovává, například).Doporučujeme uvolnit všechny nespravované prostředky v je finalizační metoda.Protože spravované prostředky jsou uvolněny nedeterministicky systémem uvolňování, není bezpečné odkazovat spravovaných prostředků ve finalizační metody, protože je možné, že uvolňování paměti má již vyčištěna spravované zdroje.
Finalizační metody jazyka Visual C++ není stejný jako Finalize metoda.(CLR dokumentace používá finalizační metodě a Finalize metoda jako synonymum).Finalize Metoda je volána uvolňování, což vyvolá každý finalizační metodě třídy řetězce dědičnosti.Na rozdíl od aplikace Visual C++ destruktory nezpůsobí volání finalizační metodě odvozených tříd kompilátoru k vyvolání finalizační metodě všechny základní třídy.
Protože kompilátor Visual C++ podporuje deterministický uvolnění prostředků, nepokoušejte se provádět Dispose nebo Finalize metod.Pokud jste obeznámeni s těmito metodami, zde je však jak finalizační metody Visual C++ a destruktor, který volá je finalizační metoda namapován Dispose vzorek:
// 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();
}
}
Spravovaný typ může také použít spravované prostředky, které chcete raději deterministically, a ne nechat uvolňování paměti uvolnit nedeterministicky v určitém okamžiku po objekt již není požadováno.Deterministický uvolnění prostředků může výrazně zlepšit výkon.
Kompilátor Visual C++ umožňuje definici destruktor deterministically vyčistit objekty.Použijte destruktor uvolnění všech prostředků, které chcete uvolnit deterministically.Finalizační metody je k dispozici, kontaktujte z destruktoru, aby se zabránilo zdvojení kód.
// destructors_finalizers_1.cpp
// 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
// ...
}
};
Je-li kód, který zpracovává váš typ nevolá destruktor, uvolňování nakonec uvolní všechny spravované prostředky.
Přítomnost destruktor neznamená přítomnost finalizační metody.Přítomnost finalizační metody však vyplývá, že musíte definovat destruktor a volat je finalizační metoda z tento destruktor.To poskytuje deterministický propuštění nespravované prostředky.
Volání destruktoru potlačí – pomocí SuppressFinalize– dokončení objektu.Pokud není volána destruktoru, finalizační metodě tohoto typu budou nakonec volány uvolňování.
Deterministically uvolnění prostředků objektu pomocí volání destruktoru může zlepšit výkon ve srovnání s umožní CLR nedeterministicky finalizovat objektu.
Kód, který je zapsán v aplikaci Visual C++ a zkompilován s použitím /clr destruktoru tohoto typu se spustí, pokud:
Objekt, který je vytvořen pomocí sémantiku zásobníku je mimo rozsah.Další informace naleznete v tématu Sémantika jazyka C++ zásobníku pro referenční typy.
Výjimka je vyvolána během výstavby objektu.
Objekt je členem objektu, jehož destruktor je spuštěna.
Volání Odstranit operátor na popisovač (Operátor popisovače objektu (^) (rozšíření komponent C++)).
Explicitní volání destruktoru.
Pokud váš typ je spotřebováváno klienta, který je napsán v jiném jazyce, je zavolán destruktor takto:
Pro volání na Dispose.
Pro volání na Dispose(void) typu.
Pokud se typ přechodu mimo z rozsahu v C# using prohlášení.
Je-li vytvořit objekt typu odkaz na spravované haldě (bez použití zásobníku sémantiky pro referenční typy), použijte try-finally syntaxe, aby bylo zajištěno, že výjimku nezabrání destruktor spuštění.
// clr_destructors.cpp
// compile with: /clr
ref struct A {
~A() {}
};
int main() {
A ^ MyA = gcnew A;
try {
// use MyA
}
finally {
delete MyA;
}
}
Pokud váš typ nemá destruktor, kompilátor vygeneruje Dispose metodu, která implementuje IDisposable.Pokud typ, který je napsán v jazyce Visual C++ a byl destruktor, který je spotřebován v jiném jazyce, volání IDisposable::Dispose na daný typ způsobí, že destruktor tohoto typu volání.Je-li typ je spotřebováno v klientovi aplikace Visual C++, nelze volat přímo Dispose; Místo toho pomocí volání destruktoru delete operátor.
Pokud váš typ nemá finalizační metody, kompilátor vygeneruje Finalize(void) metodu, která má přednost před Finalize.
Pokud je typ finalizační metody nebo destruktor, kompilátor vygeneruje Dispose(bool) metoda podle návrhového vzoru.(Informace naleznete v tématu Implementing Finalize and Dispose to Clean Up Unmanaged Resources).Nelze explicitně vytvářet nebo volejte Dispose(bool) v aplikaci Visual C++.
Pokud typ má základní třída, která odpovídá návrhového vzoru, se nazývají destruktory pro všechny základní třídy při volání destruktoru třídy odvozené.(Pokud váš typ je napsán v jazyce Visual C++, kompilátor zajišťuje, že vaše typy implementovat tento vzor.) Jinými slovy, destruktor referenční třídy zřetězen jeho základny a členy podle C++ standard – první destruktoru třídy je spustit, desktruktorů pro své členy v obráceném pořadí, ve kterém byly vyrobeny a nakonec destruktory pro jeho základní třídy v obráceném pořadí, ve kterém byly vyrobeny.
Destruktory a finalizační metody nejsou povoleny uvnitř rozhraní nebo hodnotové typy.
Finalizační metody lze pouze definovat, nebo deklarované v typu odkazu.Podobně jako konstruktoru a destruktoru finalizační metody má žádný typ návratu.
Po spuštění finalizační metodě objektu finalizační metody ve všech základních tříd se také nazývají, počínaje nejméně odvozeného typu.Finalizační metoda pro datové členy nejsou zřetězen automaticky ve finalizační metodě třídy.
Pokud finalizační metody odstraní nativní ukazatele spravovaného typu, je třeba zajistit, že odkazy na nebo prostřednictvím nativní ukazatele nejsou shromážděny předčasně; volání destruktoru spravovaného typu namísto použití KeepAlive.
V době kompilace můžete zjistit, zda byl typ finalizační metody nebo destruktoru.Další informace naleznete v tématu Podpora kompilátoru pro typové vlastnosti (C++ Component Extensions).
Následující příklad ukazuje dva typy, jeden, který má nespravované prostředky a jeden, který byl spravován prostředky, které jsou vydány deterministically.
// destructors_finalizers_2.cpp
// 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");
}