다음을 통해 공유


방법: 클래스 및 구조체 정의 및 사용(C++/CLI)

이 문서에서는 정의 하 고 사용자 정의 참조 형식 및 값 형식에 사용 하는 방법을 보여 줍니다. C++/CLI.

개체 인스턴스화

만 참조 형식과 값 형식의 관리 되는 힙에 없습니다 스택에, 네이티브 힙에 인스턴스화할 수 있습니다.

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

암시적으로 추상 클래스

암시적으로 추상 클래스 를 인스턴스화할 수 없습니다.클래스는 기본 클래스의 인터페이스 형식이 고 클래스는 모든 인터페이스의 멤버 함수를 구현 하지 않는 경우 암시적으로 추상입니다.

인터페이스에서 파생 되는 클래스에서 개체를 생성할 수 없는 경우 암시적으로 추상 클래스 임을 이유 수 있습니다.추상 클래스에 대 한 자세한 내용은 추상.

다음 코드 예제에서는 방법을 보여 줍니다.는 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) 형식의 가시성을 제어할 수 있습니다.

public형식을 포함 하는 모든 소스 파일에 표시 되는지 나타냅니다는 #using 형식이 포함 된 어셈블리에 대 한 지시문입니다.private형식을 포함 하는 소스 파일에 표시 되지 않았음을 나타냅니다는 #using 형식이 포함 된 어셈블리에 대 한 지시문입니다.그러나 private 형식은 동일한 어셈블리 내에서 표시 됩니다.기본적으로 클래스에 대 한 가시성입니다 private.

Visual C++ 2005 기본적으로 네이티브 형식은 어셈블리 외부에서는 public 액세스 가능성이 있었습니다.사용 컴파일러 경고 (수준 1) C4692 는 전용 네이티브 형식을 잘못 사용할 볼 수 있도록 합니다.사용 된 make_public pragma를 수정할 수 있는 소스 코드 파일에 네이티브 형식에 public 액세스 가능성입니다.

자세한 내용은 # 지시문 (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

이 표는 다양 한 액세스 지정자의 효과를 요약 되어 있습니다.

지정자

Effect

public

멤버는 내부와 외부의 어셈블리에 액세스할 수입니다.자세한 내용은 public (C++)를 참조하십시오.

private

멤버 안에 아니고 어셈블리 외부에서 액세스할 수 없습니다.자세한 내용은 private (C++)를 참조하십시오.

protected

멤버인 내부 및 어셈블리 외부 있지만 파생 된 형식에 액세스할 수 있습니다.자세한 내용은 보호 된 (C++)를 참조하십시오.

internal

멤버가 공용 어셈블리 내부의 어셈블리 외부에서 전용입니다.internal상황에 맞는 키워드가입니다.자세한 내용은 상황에 맞는 키워드(C++ 구성 요소 확장)을 참조하십시오.

public protected
-or-
protected public

멤버에는 공용 어셈블리 내부의 있지만 어셈블리 외부에서 보호 됩니다.

private protected
-or-
protected private

멤버는 어셈블리 내부의 보호 하지만 어셈블리 외부에서 전용입니다.

다음 샘플에서는 서로 다른 액세스 가능성이 있는, 선언 된 멤버가 public 형식이 보여주며 어셈블리 내에서 해당 멤버의 액세스를 보여 줍니다.

// 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 컴파일러 함수 이름에 직접 기본 클래스의 함수 숨겨지지 않고 있지만 컴파일러 이름으로 숨김 클래스 상속 체인에서 발견 되 면 해당 이름으로 숨김 동작을 계속 합니다.

서명으로 숨겨집니다 의미론 개체에서 함수를 호출할 때 컴파일러 함수 호출을 충족 수 함수가 포함 된 가장 많이 파생 된 클래스를 식별 합니다.컴파일러가 호출을 수행 하지 못했습니다 클래스에서 하나의 함수가 있으면 그 함수를 호출 합니다.클래스에서 호출을 수행 하지 못했습니다 함수가 두 개 이상 있으면 컴파일러 사용 하 여 호출할 함수를 확인할 수 있는 확인 규칙 오버 로드 합니다.오버 로드 규칙에 대 한 자세한 내용은 함수 오버 로드.

지정 된 함수 호출의 경우 함수는 기본 클래스에서 파생 된 클래스에서 함수 보다 조금 더 나은 일치를 쉽게 서명이 있을 수 있습니다.그러나 함수는 파생된 클래스의 개체를 명시적으로 호출 된 경우 파생된 클래스에 있는 함수의 호출 됩니다.

반환 값은 함수 시그니처의 일부가 아닙니다 때문에 같은 이름을 가진 및 같은 수 및 종류의 인수는 파생 클래스 함수를 사용 하는 경우 반환 값의 형식에서 다른 경우에 기본 클래스 함수가 숨겨집니다.

다음 샘플에서는 함수는 기본 클래스에서 파생 클래스에서의 함수에 의해 숨겨져 있는 표시 됩니다.

// 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.Managed Extensions for 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(공용 언어 런타임 컴파일)을 참조하십시오.

다음 샘플에서는 경우에 복사 생성자가 생성 되지 않습니다.

// 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++ 클래스의 소멸자 동작 Managed Extensions for C++ 다릅니다.이 변경 내용에 대한 자세한 내용은 소멸자 의미의 변경 내용를 참조하십시오.

CLR 가비지 수집기가 사용 하지 않는 관리 되는 개체를 삭제 하 고 더 이상 필요 없는 경우 해당 메모리를 해제 합니다.그러나 형식 가비지 수집기에서 해제 하는 방법을 알지 못하는 리소스를 사용할 수 있습니다.이러한 리소스 관리 되지 않는 리소스는 리소스 라고 (원시 파일 처리, 예를 들어).종료자에서 관리 되지 않는 리소스를 모두 해제 하는 것이 좋습니다.불명확 하 게 가비지 수집기가 관리 되는 리소스를 해제 하기 때문에 있기 때문에 종료자에서 관리 되는 리소스가 가비지 수집기는 관리 되는 리소스를 이미 치료는 참조 하는 것이 안전 하지 않습니다.

Visual C++ 종료자는 동일 하지 않습니다는 Finalize 메서드가 있습니다.(설명서 CLR 종료자를 사용 하 고 Finalize 메서드 synonymously).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++ 컴파일러 정의의 개체를 명확 하 게 정리 하는 소멸자가 있습니다.소멸자를 사용 하 여 명확 하 게 해제 하려면 모든 리소스를 해제 합니다.종료 자가 있으면, 코드 중복을 피하기 위해 소멸자를 호출 합니다.

// 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) 형식입니다.

  • 범위에서 C# 형식을 벗어날 경우 using 문.

(스택 의미 참조 형식에 대 한 사용지 않습니다) 힙의 관리 되는 참조 형식의 개체를 만들 경우 사용 try-finally 구문 예외가 소멸자 실행 차단 되지 않는 확인 합니다.

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

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

에 소멸자가 있으면 컴파일러가 생성 하는 Dispose 메서드 구현 IDisposable.호출 하는 Visual 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++ 구성 요소 확장)을 참조하십시오.

다음 샘플에서는 두 형식이 관리 되지 않는 리소스를 가진, 하나 하나 명확 하 게 해제 된 리소스 관리를 보여 줍니다.

// 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++ 구성 요소 확장)