共用方式為


如何:定義與使用類別和結構 (C++/CLI)

本文說明如何定義和使用使用者定義的參考型別和實值型別在 C++/CLI。

物件執行個體化

(ref) 參考型別和實值型別只能在 Managed 堆積上,不在堆疊上或在原生堆積上。

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

輸入可視性。

您可以控制 Common Language Runtime (CLR) 型別的可視性,以便,,如果組件參考,組件中的型別可以是可見或不可見的在組件之外。

public 表示型別看見包含組件的 #using 指示詞包含型別的所有原始程式檔。 private 表示型別不會看見包含組件的 #using 指示詞包含型別的原始程式檔。 不過,私用型別位於相同的組件內為可見。 根據預設,類別的可視性則為 private。

預設會在 Visual C++ 2005 以前,原生型別在組件外部的公用存取範圍。 編譯器警告 (層級 1) C4692 可協助您查看位置不正確地使用私用原生型別。 使用 make_public Pragma 給公用存取範圍的原生型別不能修改原始程式碼檔案。

如需詳細資訊,請參閱# 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

成員存取內部和外部組件。 如需詳細資訊,請參閱 公用 (C++)

private

成員無法存取,在組件之內。 如需詳細資訊,請參閱 私用 (C++)

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

  

公用和私用原生類別。

原生型別可以從 Managed 型別參考。 例如,在 Managed 型別的函式可以接受型別為原生結構的參數。 如果 Managed 型別和函式是公用的組件中,則原生型別也必須是公用的。

// 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 型別 (例如,類別或結構可以具有可用來初始化靜態資料成員的靜態建構函式。 在型別的任何靜態成員第一次,存取靜態建構函式呼叫一次並呼叫。

執行個體建構函式一定會執行靜態建構函式。

如果類別有靜態建構函式,編譯器無法內嵌呼叫建構函式。 編譯器無法內嵌呼叫函式的任何成員類別是實值型別 (Value Type),具有靜態建構函式並不具有執行個體建構函式。 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 指標型別為「Handles」。 在實值型別上 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

  

隱藏的簽章函式

在 Standard 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 (Common Language Runtime 編譯)

下列範例示範如何複製建構函式時不會產生。

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

  

解構函式或完成項

在參考型別的解構函式實作資源判斷清除。 完成項來清除 Unmanaged 資源,而且可以呼叫決定性地由解構函式或 nondeterministically 由記憶體回收行程。 如需標準 C++ 中的解構函式的詳細資訊,請參閱 解構函式 (C++)

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

解構函式會在 Managed Visual C++ 類別的使用 Managed Extensions for C++ 不同。 如需這項變更的詳細資訊,請參閱解構函式語意的變更

不再需要時, CLR 記憶體回收行程刪除未使用的 Managed 物件並釋放其記憶體它們。 不過,型別可以使用記憶體回收行程不會釋放的資源。 這些資源稱為 Unmanaged 資源 (例如原生檔案控制代碼,)。 我們建議您釋放在完成項的所有 Unmanaged 資源。 由於記憶體回收行程釋放 Managed 資源 nondeterministically,指完成項的 Managed 資源是不安全的,因為是可能的記憶體回收行程已清除了 Managed 資源。

Visual C++ 完成項與 Finalize 方法。 (CLR 文件使用完成項和 Finalize 方法的定義方式)。 Finalize 方法由記憶體回收行程呼叫,在類別繼承鏈結叫用每個完成項。 不同於 Visual C++ 解構函式,衍生類別完成項呼叫不會使編譯器會叫用所有基底類別的完成項。

由於 Visual C++ 編譯器支援資源決定版本,不要嘗試執行 DisposeFinalize 方法。 不過,因此,如果您熟悉這些方法,這個方式 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();
   }
}

Managed 型別也可以使用您想發行判斷對應的 Managed 資源和不接聽任何記憶體回收行程釋放 nondeterministically,在不再需要物件之後。 資源判斷版本可以大幅改善效能。

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

如果您使用型別的程式碼不會呼叫解構函式,記憶體回收行程最終釋放所有的 Managed 資源。

解構函式的出現不表示完成項時發生。 不過,完成項出現提示您必須定義解構函式和呼叫該解構函式的完成項。 這提供 Unmanaged 資源決定版本。

呼叫隱藏由使用 SuppressFinalize衍生物件的最終處理的解構函式。 如果解構函式未呼叫方法,將型別的完成項會由記憶體回收行程最後呼叫。

判斷來清除物件的資源是透過呼叫解構函式可以改善效能比較讓 CLR nondeterministically Finalize 物件。

程式碼在 Visual C++ 撰寫,並編譯使用 /clr 執行型別的解構函式,如果:

如果您的型別撰寫另一種語言的用戶端使用,解構函式呼叫如下所示:

  • 在對 Dispose的呼叫。

  • 在對 Dispose(void) 的呼叫會型別。

  • 如果型別超出 C# 中的 using 陳述式的範圍。

如果您建立一個參考型別的物件在 Managed 堆積上 (不使用參考型別的堆疊語意),請使用 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上的 Finalize(void) 方法。

如果型別具有完成項或解構函式,編譯器會根據設計模式產生 Dispose(bool) 方法。 (如需詳細資訊,請參閱 Implementing Finalize and Dispose to Clean Up Unmanaged Resources)。 您不能明確建立或呼叫在 Visual C++ 的 Dispose(bool)

如果型別具有符合設計模式的基底類別,所有基底類別的解構函式,在衍生類別中的解構函式呼叫時。 (如果您的型別以 Visual C++ 撰寫,編譯器會確保您的型別會實作模式)。換句話說,參考類別中的解構函式其基底和成員的依 C++ 標準第一個類別的解構函式,然後執行其成員的解構函式會建構命令的相反的最後和其基底類別的解構函式會在建構命令的相反。

解構函式或完成項不提供內實值型別或介面。

完成項在參考型別上只能定義或宣告。 像建構函式和解構函式,完成項沒有傳回型別。

在物件的完成項執行後,在任何基底類別完成項從最少衍生型別開始,也會呼叫。 資料成員的完成項不會自動繫結至類別的完成項。

如果完成項刪除在 Managed 型別的原生指標,您必須確定參考或透過原生指標提前沒有收集;呼叫 Managed 型別的解構函式而不是使用 KeepAlive

在編譯時期,您可以偵測型別是否具有完成項或解構函式。 如需詳細資訊,請參閱型別特性的編譯器支援 (C++ 元件擴充功能)

下一個範例會顯示兩個型別,有 Unmanaged 資源有 Managed 資源決定性地釋放的一個。

// 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++ 元件擴充功能)