Как Классы и структуры создания экземпляра

В данной статье показано, как определять и использовать определяемые пользователем типы значений и ссылочные типы в C++/CLI.

Описание

Создание объектов

Неявно абстрактные классы

Видимость типа

Видимость члена

Открытые и закрытые собственные классы

Статические конструкторы

Семантика этого указателя

функции Мостовь--сигнатуры

Конструкторы копирования

Деструкторы и завершения

Создание объектов

Типы и типы значений (ref) ссылки можно создавать только в управляемой куче, не в стеке или в собственной куче.

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

Неявно абстрактные классы

неявно абстрактный класс не создаются. Абстрактный базовый класс неявно, если тип класса и интерфейса класса не реализует всего функции-члены интерфейса.

Если не удалось создать объекты из класса, который является производным от интерфейса, причиной может быть неявно, что класс является абстрактным. Абстрактные классы Дополнительные сведения о см. в разделе abstract.

В следующем примере кода показано, как класс MyClass не создаются, поскольку функция MyClass::func2 не реализована. Пример позволяет компилировать, комментарий 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.
}

Видимость типа

Элемент управления можно видимость (CLR) типов среды CLR, что, если сборку, типы в сборке могут быть видны или не видны вне сборки.

public означает, что тип является видимым в любой файл источника, который содержит директиву #using для сборки, содержащей тип. private означает, что тип не отображается в файлы источника, которые содержат директиву #using для сборки, содержащей тип. Однако закрытым типам видны в пределах одной сборки. По умолчанию видимость для класса private.

По умолчанию в Visual C++ 2005 C, собственные типы имеют общую специальных возможностей за пределами сборки. Предупреждение компилятора (уровень 1) C4692 может помочь понять, где закрытые собственные типы используются неправильно. Используйте директиву pragma make_public, чтобы получить открытую специальных возможностей в собственный тип в файле исходного кода, нельзя изменять.

Для получения дополнительной информации см. Директива #using (C++).

В следующем примере показано, как объявлять типы и определения их специальных возможностей и извлекать эти типы в сборку. Конечно, если сборка с закрытым типам указывается с помощью #using, только открытые типы в сборке видимы.

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

Output

  

Теперь, рассмотрим следующий переписать предыдущий пример таким образом, чтобы он будет построен в виде библиотеки 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");}
};

В следующем примере показано, как получить доступ к типы за пределами сборки. В этом примере клиент использует компонент, из предыдущего примера.

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

Output

  

Видимость члена

Это можно сделать доступ к члену открытого класса из одной и той же сборки другой, чем доступ к нему извне сборки с помощью пар описателей public, protected и private доступа

В этой таблице перечислены результаты различных описателей доступа.

класса хранения

Действие

public

Член доступные внутри и вне сборки. Дополнительные сведения см. в разделе public (C++).

private

Участник недоступен, а внутри и вне сборки. Дополнительные сведения см. в разделе private (C++).

protected

Член доступные внутри и вне сборки, но только к производным типам. Дополнительные сведения см. в разделе protected (C++).

internal

Член является общим внутри сборки, но в этом случае за пределами сборки. internal контекстно-зависимое ключевое слово. Для получения дополнительной информации см. Контекстные ключевые слова (расширения компонентов C++).

public protected
-or-
protected public

Член является общим внутри сборки, но защищен за пределами сборки.

private protected
-or-
protected private

Член защищен закрытый внутри сборки, но за пределами сборки.

В следующем примере показано открытый тип, который имеет члены, объявленные с различными специальными возможностями и затем отображает получения этих членов внутри сборки.

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

Output

  

Теперь рассмотрим следующий построение в предыдущем примере в виде библиотеки 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("=======================");
   }
};

В следующем примере компонент, созданный в предыдущем примере, и поэтому показано, как получить доступ к членам извне сборки.

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

Output

  

Открытые и закрытые собственные классы

Собственный тип можно ссылаться из управляемого типа. Например, функция в управляемом типе может принимать параметр, тип которого собственная структура. Если управляемый тип и функция открытым в сборке, собственный тип также должен быть открытым.

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

Теперь создайте файл исходного кода, использующего собственный тип:

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

Теперь, компилировать клиент:

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

Статические конструкторы

CLR тип- для примера, класса или структуры являются может иметь статический конструктор, который можно использовать для инициализации статические члены данных. Вызывается не более одного раза, и вызывает статический конструктор до любого статический член типа получен в первый раз.

Конструктор экземпляра всегда выполняется после статического конструктора.

Компилятор не может последовательно вызов конструктора, если класс имеет статический конструктор. Компилятор не может последовательно вызов любой функцию-член, если класс тип значения, имеет статический конструктор, и нет конструктора экземпляра. CLR может последовательно вызов, но компилятор не может.

Определите статический конструктор как функция закрытого члена, поскольку, не была вызываться только средой CLR.

Дополнительные сведения о статических конструкторов см. в разделе Практическое руководство. Определение статического конструктора интерфейса (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();
}

Output

  

Семантика этого указателя

При использовании Visual C++ для определения типов, указатель this в ссылочный тип дескриптора типа «». Указатель this в типе значения типа «внутреннего указателя».

Семантика этого является указателем this может вызвать непредвиденное расширение функциональности при вызове индексатора по умолчанию. В следующем примере показано, как правильно подключитесь к нему по умолчанию как в ссылочного типа, так и в списке значений.

Дополнительные сведения см. в следующем разделе.

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

Output

  

Функции Мостовь--сигнатуры

В стандартном языке C++, функция в базовом классе скрыта функцией с тем же именем в производном классе, даже если функция производного класса не имеют одинаковое число или тип параметров. Это называется семантика мостовь -- имени. В ссылочного типа, функция в базовом классе может быть скрыта функцией в производном классе, и имя и список параметров совпадают. Это как семантика мостовь-- сигнатуры.

Класс считается классом мостовь -- сигнатуры, когда все свои функций помечены в метаданных как hidebysig. По умолчанию все классы, созданные в /clr имеют функции hidebysig. Однако класс, компилироваться с помощью /clr:oldSyntax не имеет функции hidebysig; вместо этого они функции мостовь -- имени. Если класс содержит функции hidebysig, компилятор не скрывает функцию по имени во всех прямых базовым классом, но если компилятор обнаруживает класс мостовь -- name в цепочке наследования, продолжается это расширение функциональности мостовь -- имени.

В мостовь семантикой -- сигнатуры, когда функция вызывается в объекте, компилятор определяет наиболее производный класс, который содержит функцию, которая может быть вызов функции. Если только одной функции в классе, который может быть вызов, компилятор вызывает эту функцию. Если несколько функций в классе, который может быть вызов, компилятор использует правила разрешения перегруженных версий, определить функцию вызвать. Правила перегруженной Дополнительные сведения о см. в разделе Перегрузка функций.

Для вызова указанной функции функции в базовом классе может иметь подпись, которая позволяет использовать несколько является более подходящим, чем функция в производном классе. Однако если функция явно называется объекта производного класса, то вызывается функция в производном классе.

Так как возвращаемое значение не является частью сигнатуры функции, функция базового класса скрыта, если она имеет то же имя и принимает те же количество и тип аргументов, как функция производного класса, даже если она отличается в типе возвращаемого значения.

В следующем примере показывается, что функция в базовом классе не скрыта функцией в производном классе.

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

Output

  

Следующий пример демонстрирует, что компилятор Visual C++ вызывает функцию в наиболее производная класса ровной при необходимости, что соответствует одному или нескольким из параметр- и вызывает преобразование функций в базовом классе, который является более подходящим для вызова функции.

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

Output

  

В следующем примере показано, что можно скрывать функции, даже если базовый класс содержит ту же сигнатуру, как производный класс.

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

Output

  

В следующем примере определяется компонент, компилироваться с помощью /clr:oldSyntax. Классы, которые определяются с помощью управляемых расширений для C++ имеют C функции-члены мостовь -- имени.

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

В следующем примере используется компонент, из предыдущего примера. Обратите внимание, что функция мостовь -- подписи не применяется в базовые классы типов, компилированы с помощью /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
}

Конструкторы копирования

Стандарт C++ говорится, что конструктор копии при перемещении объекта, такие как объект создан и разрушан на этих же адрес.

Однако при /clr используется компилироваться и функцию, скомпилирована в MSIL вызывает собственная функция, собственный класса или более чем от передает значение и где собственный класс содержит конструктор копии и/или деструктор, не вызывают отсутствует конструктор копий и объект уничтожается в другой адреса, где он был создан. Это может вызвать проблемы, если класс содержит указатель на себя, или, если код отслеживает объекты адреса.

Для получения дополнительной информации см. /clr (компиляция CLR).

В следующем примере показано, когда не создают конструктор копий.

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

Output

  

Деструкторы и завершения

Деструкторы в ссылочном типе выполняют детерминистскую уборку ресурсов. Метод завершения очищает неуправляемых ресурсов и может вызываться являются детерминированными деструктором или недетерминированно сборщиком мусора. Дополнительные сведения о деструкторах в стандарте Языка C++ — см. в разделе Деструкторы (C++).

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

Расширение функциональности деструкторов в управляемом классе Visual C++ отличается от управляемых расширений для C++. Дополнительные сведения об этом изменении см. в разделе Изменения в семантике деструктора.

Сборщик мусора среды CLR удаляет неиспользуемые управляемые объекты и выпуски их память, если они больше не требуются. Однако тип может использовать ресурсы, сборщик мусора не знает, как выпуска. Эти ресурсы в неуправляемых ресурсов (собственные дескрипторы файлов, например). Рекомендуется выпуске все неуправляемые ресурсы в методе завершения. Поскольку управляемые ресурсы освобождаются недетерминированно сборщиком мусора, небезопасно ссылаться в управляемые ресурсы в методе завершения, поскольку возможно, что сборщик мусора уже очищал вверх, управляемый ресурс.

Завершение Visual C++ — не то же, что и метод Finalize. (Документация CLR завершения и метод Finalize синонимно). Метод Finalize вызывается сборщиком мусора, которая вызывает каждый метод в цепочке наследования классов. В отличие от деструкторы Visual C++ метода завершения производного класса не вызывает завершение вызова компилятора во всех базовых классах.

Поскольку выпуск технология поддерживает компилятора Visual C++ детерминированный ресурсов не пытается реализовать методы Dispose или Finalize. Однако если вы знакомы с этими методами, описание завершение Visual C++, который вызывает деструктор сопоставление завершения в шаблон Dispose:

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

Управляемый тип также может использовать управляемые ресурсы, которые предпочитали бы освобождение являются детерминированными и не оставляя к сборщику мусора получения освобождение недетерминированно в некоторой точке после того, как объект больше не нужен. Детерминированный выпуск ресурсов может значительно повысить производительность.

Компилятор Visual C++ позволяет C определение деструктора являются детерминированными очистить объекты. Используйте деструктор для освобождения любых ресурсов, которые необходимо освобождать являются детерминированными. Если завершение присутствует, вызовите его из деструктора, чтобы избежать дублирования кода.

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

Если код, использующий данный тип не вызывает деструктор, сборщик мусора выпуски концов все управляемые ресурсы.

Наличие деструктора не подразумевает наличие завершения. Однако наличие завершения означает, что необходимо указать деструктор и вызвать метод завершения из деструктора. Это обеспечивает для детерминистского выпуска неуправляемых ресурсов.

Вызов деструктора подавлять- использованием SuppressFinalize— метода завершения объекта. Если деструктор не вызывается, завершение пользовательского типа в конечном счете будет вызвано сборщиком мусора.

Являются детерминированными очистку ресурсов объекта класса путем вызова деструктора может повысить производительность сравненную с предоставление CLR недетерминированно завершает объект.

Кода, написанного на Visual C++ и компилироваться с помощью /clr выполняется деструктор типа, если:

Если тип использовать клиент, на котором написан на другом языке, деструктор вызывается следующим образом:

  • При вызове Dispose.

  • При вызове Dispose(void) типа.

  • Если тип выходит за пределы области действия в инструкцию using C#.

При создании объекта ссылочного типа в управляемой куче (используя не семантику стека для ссылочных типов), используйте синтаксис попробуйте — окончательн, чтобы убедиться, что исключение не препятствует деструктор не выполняются.

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

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

Если тип имеет деструктор, компилятор не генерирует метод Dispose, реализующий IDisposable. Если тип, написанного на языке C++ имеет деструктор, используемого из другого языка, вызывая IDisposable::Dispose на этом причины типа деструктор типа, назначив. Если тип будет использоваться из клиента Visual C++, нельзя непосредственно вызов Dispose; вместо этого вызовите деструктор с помощью оператора delete.

Если тип имеет завершение, компилятор не генерирует метод Finalize(void), переопределяет Finalize.

Если тип имеет или завершение или деструктор, компилятор не генерирует метод Dispose(bool) согласно шаблону разработки. (Дополнительные сведения см. в разделе Implementing Finalize and Dispose to Clean Up Unmanaged Resources). Нельзя явно автор или вызов Dispose(bool) в Visual C++.

Если тип имеет базовый класс, который соответствует шаблону разработки, деструкторы для всех базовых классов вызываются при вызове деструктора для производного класса. (Если тип записывается в Visual C++, компилятор гарантирует, что собственные типы реализуют этот шаблон). Другими словами, выполняются цепочек деструктор ссылочного класса в их базы и члены, определенные деструктор стандартн- первого класса C++ и деструкторы для членов в обратном порядке, в котором они были созданы, и наконец деструкторы для базовых классов в обратном порядке, в котором они были созданы.

Не может деструкторам и завершениям внутренние типы значений и интерфейсы.

Завершение можно определить только или объявления в ссылочного типа. Как и конструкторы и деструкторы, завершение не имеет возвращаемый тип.

После завершения выполнения метода завершения объекта, во всех базовых классах также называются, начиная с наименьшим производным типом. Метод завершения для элементов данных автоматически не прикован, на которое расширение класса.

Если завершение удаления собственный указатель в управляемом типе, необходимо убедиться, что ссылки на или через собственный указатель преждевременно не собираются. вызовите деструктор для управляемого типа вместо использования KeepAlive.

Во время компиляции можно выберите имеет ли тип завершение или деструктор. Для получения дополнительной информации см. Поддержка характеристик типов компилятором (расширения компонентов C++).

В следующем примере показаны 2 одного типа, с неуправляемыми ресурсами и один, управляемый ресурсы, являются детерминированными, высвобождаются.

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

См. также

Ссылки

Классы и структуры (расширения компонентов C++)

Классы и структуры (расширения компонентов C++)