方法: クラスと構造体を定義および使用する (C++/CLI)
ここでは 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;
}
暗黙的に抽象クラス
暗黙的に抽象クラスは インスタンス化できません。クラスは、クラスの基本型がインターフェイスであり、そのクラスがインターフェイスのメンバー関数を実装するすべて暗黙的に抽象クラスです。
インターフェイスから派生したクラスのオブジェクトを構築する理由は、クラスが暗黙的に抽象であることがあります。抽象クラスの詳細については、概要を参照してください。
次のコード例は、関数 MyClass::func2 は実行されないので、MyClass のクラスがインスタンス化できないことを示します。例をコンパイルできるようにする 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です。
既定では、Visual C++ 2005 以前では、ネイティブ型がアセンブリの外部でパブリック アクセシビリティがありました。プライベート ネイティブ型が不適切に使用されているかを確認することを コンパイラの警告 (レベル 1) C4692 を有効にします。ネイティブにパブリック アクセスを提供するために 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();
}
出力
これは 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;
}
出力
メンバーの表示
ペアのアクセス指定子 public、protectedと privateを使用してアセンブリの外部からのアクセスとは別に、同じアセンブリからパブリック クラスのメンバーにアクセスできます。
この表は、さまざまなアクセス指定子の効果を示しています:
指定子 |
効果 |
---|---|
|
メンバーがアクセスできる内部および外部アセンブリです。詳細については、「パブリック (C++)」を参照してください。 |
|
メンバーは、アセンブリ内での外側にアクセスできません。詳細については、「プライベート (C++)」を参照してください。 |
|
メンバーは派生型にのみアクセスできますが、内部および外部アセンブリです。詳細については、「プロテクト (C++)」を参照してください。 |
|
メンバーは、アセンブリがアセンブリの外部でプライベート内でパブリックです。internal は状況依存のキーワードです。詳細については、「状況依存のキーワード (C++ コンポーネント拡張)」を参照してください。 |
|
メンバーは、アセンブリ内でパブリックですが、アセンブリの外部で保護されます。 |
|
メンバーは、アセンブリの外部のプライベート アセンブリ内で保護されます。 |
次の例では、異なるアクセシビリティで宣言されたあり、そのアセンブリの中からそれらのメンバーのアクセスを示すメンバーがパブリックの型を示します。
// 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();
}
出力
これは 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();
}
出力
パブリック メソッドおよびプライベート ネイティブ クラス
ネイティブ型はマネージ型から参照できます。たとえば、マネージ型の関数では、型がネイティブ構造体であるパラメーターを受け取ることができます。マネージ型と関数がアセンブリ内でパブリックである場合、ネイティブ型は、パブリックである必要があります。
// 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 からのみ呼び出すことを意味するため、プライベート メンバー関数と静的コンストラクターを定義します。
静的コンストラクターに関する詳細については、方法: interface 静的コンストラクターを定義する (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();
}
出力
このポインターのセマンティクス
型を定義するために、Visual C++ を使用している場合は、参照型の this のポインターは型 "ハンドル" です。値型の this のポインターは型 "内部ポインター" です。
既定のインデクサーが呼び出されたときにこれらの this のポインターは異なる意味は、予期しない動作が発生することがあります。次の例は ref 型と値型のどちらの既定のインデクサーにアクセスする正しい方法を示しています。
詳細については、次のトピックを参照してください。
// 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();
}
出力
非ごとに定義関数
標準 C++ では、基本クラスの関数は、派生クラスで同じ名前を持つ関数によってクラスの関数にパラメーターが同じ数の種類またはない場合でも、非表示になります。これは 非ごとに名前の セマンティクスと呼ばれます。参照型では、基本クラス関数は、派生クラスの関数によって名前とパラメーター リストの両方が同じ場合だけを非表示にすることはできません。これは 非ごとに定義の セマンティクスと呼ばれます。
クラスはすべて関数が hidebysigとしてメタデータでマークされていると非ごとに定義のクラスと見なされます。既定では、/clr の下に作成したすべてのクラスに hidebysig の関数があります。ただし、/clr:oldSyntax を使用してコンパイルするクラスに hidebysig 関数はありません; 代わりに、非表示の関数ごとに名前です。クラスに hidebysig の関数が含まれる場合、コンパイラは関数を直接基本クラスに名前で非表示になりません、コンパイラが継承チェーンの隠ぺいごとに名前のクラスが発生した場合は、その非ごとに名前の動作を継続します。
非ごとに定義のセマンティクスの下で、関数がオブジェクトで呼び出されると、関数呼び出しを満たすことができる関数を含む大部分の派生クラスを識別します。呼び出しを満たすことができるクラスに、1 台の関数がある場合は、機能するコンパイラを呼び出します。呼び出しを満たすことができるクラスに複数の関数の場合は、を呼び出すか、関数を決定するコンパイラを使用するオーバーロードの解決は制御します。オーバーロードの規則の詳細については、関数オーバーロードを参照してください。
特定の関数呼び出しでは、基本クラスの関数は、派生クラスの関数によりも優先の一致を定義するがある場合があります。ただし、関数を明示的に派生クラスのオブジェクトか、派生クラスの関数が呼び出されます。
戻り値が関数のシグネチャと見なされないため、クラス関数は戻り値の型が異なっても同じ名前を持ち、クラス関数と同じ数と種類引数を取る非表示になります。
次の例では、基本クラスの関数は派生クラスの関数によって非表示になっていないことを示します。
// 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();
}
出力
次の例は、変換がの一つ以上に一致するようにパラメーター、および関数呼び出しにより適合するな基本クラスの関数を呼び出さないように要求された場合は、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);
}
出力
次の例では基本クラスと派生クラスと同じシグネチャに関係なく、関数を非表示にすることが可能であることを示します。
// 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);
}
出力
次の例では /clr:oldSyntaxを使用してコンパイルされたコンポーネントを定義します。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 がコンパイルに使用されるネイティブ クラスにコピー コンストラクターやデストラクターがある場合は値 1 を渡すと、さらに 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);
}
出力
デストラクター、およびファイナライザー
参照型のデストラクターはリソースの確定的なクリーンアップを実行します。ファイナライザーはアンマネージ リソースをクリーンアップし、デストラクターまたは非確定的にガベージ コレクターによって確定的に呼び出すことができます。標準 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++ コンパイラは、クリーンアップすることをデストラクターの定義が確定的にオブジェクトができます。解放し、確定的にするすべてのリソースを解放するために、デストラクターを使用します。ファイナライザーがある場合は、コードの重複を回避するために、デストラクターから、を呼び出します。
// 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 を使用してコンパイルされた型のデストラクターを実行する:
スタックのセマンティクスを使用して作成されたオブジェクトがスコープから外れるため詳細については、「参照型の C++ スタック セマンティクス」を参照してください。
例外は、オブジェクトの構築時にスローされます。
オブジェクトは、デストラクターが実行されているオブジェクトのメンバーです。
ハンドル (オブジェクト演算子 (^) へのハンドル (C++ コンポーネント拡張)) の 削除 の演算子を呼び出します。
明示的にデストラクターを呼び出します。
独自の型が別の言語で記述されたクライアントによって実装されている場合、デストラクターは次のように呼び出します:
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を参照)。明示的に Visual C++ の Dispose(bool) を作成したり、呼び出すことができません。
型のデザイン パターンに準拠する基本クラスがある場合、すべての基本クラスのデストラクターは、派生クラスのデストラクターが呼び出されるときに呼び出されます。独自の型が Visual C++ で記述されており (、コンパイラは、型でこのパターンを実装することを確認します。)つまり、最初 C++ 標準で指定される基本クラスとメンバーへの参照のクラスのチェーンのデストラクターは、クラス デストラクター、およびそれらの構築、finally の構築された順序の順序の基本クラスのデストラクターが実行される順序の順序のメンバーのデストラクター。
デストラクター、およびファイナライザーは内部の値型またはインターフェイスは表示されません。
ファイナライザーは参照型でのみ定義または宣言できません。コンストラクターとデストラクターのように、ファイナライザーに戻り値の型がありません。
オブジェクトのファイナライザーを実行した後で、基本クラスのファイナライザーは、最小限の派生型には、呼び出されます。データ メンバーのファイナライザーはクラスのファイナライザーに自動的にチェーンつながれません。
ファイナライザーがマネージ型のネイティブ ポインターを削除すると、ネイティブ ポインターにまたはを通じた参照が途中で収集されません。を確認してください; KeepAliveを使用する代わりにマネージ型のデストラクターを呼び出します。
コンパイル時に、型にデストラクターまたはファイナライザーがあるかどうかを検出できます。詳細については、「型の特徴のコンパイラ サポート (C++ コンポーネント拡張)」を参照してください。
次の例では 2、1 種類のアンマネージ リソースが、確定的に解放するマネージ リソースである 1 を示します。
// 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");
}