C++/CLIは,.NET FrameworkのCLI(Common Language Infrastructure)向けにC++を拡張したプログラム言語です。 &bold(){目次} #contents() *公開時期 2005年 *概要 -C++/CLIは,CLI向けにC++を拡張したプログラム言語 -C++/CLIでは、同一コード内でWin32 API、C標準ライブラリ、C++標準ライブラリ、.NET Frameworkクラスライブラリを呼び出すことが可能 -アンマネージド(ネイティブ)のコードは従来のC++の構文で記述し、マネージドのコードはref、^、%などのキーワードを使用し記述する -前身はC++マネージ拡張(Managed Extensions for C++) -C++マネージ拡張がCLR(Common Language Runtime)向けに拡張されたC++であるのに対し、C++/CLIはCLI向けに拡張されたC++ -C++/CLIに対応したVisual StudioはVisual Studio 2005以降 -国際標準化機関のEcma Internationalで規格標準化されている *言語仕様 **クラスの宣言 C++/CLIではガーベッジコレクションが追加されました。 ガーベッジコレクションが働くマネージドヒープ上にクラスを作成する場合、refキーワードを使用します。 #highlight(csharp){{ ref class MyClass { }; }} **トラッキング ハンドル マネージドヒープ上にインスタンスを作成する場合、gcnewキーワードを使用します。 gcnewで生成されたインスタンスへのポインタを取得する場合、ガーベッジコレクションによりメモリアドレスが変わるためC++のポインタ * は使用出来ず、 トラッキング ハンドル ^ を使用します。 #highlight(csharp){{ ref class MyClass { }; int main() { MyClass^ myClass = gcnew MyClass; //以下はコンパイルエラーとなる。 //MyClass* myClass = gcnew MyClass; return 0; } }} **トラッキング 参照 gcnewで生成されたインスタンスへの参照を取得する場合、C++の参照 & は使用できず、トラッキング 参照 % を使用します。 #highlight(csharp){{ ref class MyClass { }; int main() { MyClass^ a = gcnew MyClass; MyClass% s = *a; MyClass^% t = a; //初期化が必要なため以下はコンパイルエラーとなる。 //MyClass% u; MyClass^ b = gcnew MyClass; //再設定は不可なため以下はコンパイルエラーとなる。 //s = *b; return 0; } }} **nullptr C++では、ポインタがなにもさしていない状態を表す際NULLを使用します。 しかしNULLは0であり、C++/CLIではInt32型の数値となってしまいます。 そのためC++/CLIでは別途、ハンドルがなにもさしていない状態を表すキーワードとしてnullptrが用意されています。 #highlight(csharp){{ int main() { System::String^ s =nullptr; //以下はコンパイルエラーとなる。 //System::String^ s =NULL; return 0; } }} **デストラクタとファイナライザ C++/CLIのオブジェクトは、ガーベージコレクション時に呼ばれるファイナライザにて解放処理を行います。呼び出されるタイミングはガーベージコレクションが判断します。 ただリソースなど、不必要となった時点で明示的に解放すべきものがあります。その場合はdelete呼び出し時に呼ばれるデストラクタにて解放処理を行います。 デストラクタが呼ばれるとファイナライザは呼ばれなくなります。 gcnewを使用せず作成したオブジェクトの場合は、スコープを抜けた時点でデストラクタが呼ばれます。 C#では、オブジェクトを明示的に開放する場合、呼び出し側でusingステートメントを記述し、呼び出されるクラスはIDisposableインターフェイスを実装する必要がありましたが、C++/CLIのデストラクタではその手間が省かれています。 #html2(){{{{{{ <TABLE border="1" cellspacing="0" cellpadding="2"> <TBODY> <TR> <TD>名前</TD> <TD>宣言</TD> <TD>呼び出されるタイミング</TD> <TD>C#では </TD> </TR> <TR> <TD>デストラクタ</TD> <TD>~MyClass()</TD> <TD>gcnewで生成した場合は、delete呼び出し時<BR> gcnewを使用せず作成した場合は、スコープを抜けた時</TD> <TD>Dispose()</TD> </TR> <TR> <TD>ファイナライザ</TD> <TD> !MyClass()</TD> <TD>ガーベージコレクションによる解放時</TD> <TD>デストラクタ</TD> </TR> </TBODY> </TABLE> }}}}}} #highlight(csharp){{ ref class MyClass { public: // コンストラクタ MyClass() { } // デストラクタ ~MyClass() { } // ファイナライザ !MyClass() { } }; int main() { MyClass myclass; MyClass^ pmyClass = gcnew MyClass(); //deleteを呼ぶとデストラクタが呼ばれ、deleteを呼ばないとガーベージコレクションの判断したタイミングでファイナライザが呼ばれる delete pmyClass; return 0; }//myClassのデストラクタが呼ばれる }} **プロパティ C++/CLIではC#と同様にプロパティが使用できます。 #highlight(csharp){{ ref class MyClass{ private: int value; public: property int Value { int get(void) { return value; } void set(int value) { value = value; } } }; int main() { MyClass^ myClass = gcnew MyClass(); myClass->Value = 10; return 0; } }} setアクセサ、getアクセサを省略し記述すことも可能です。 #highlight(csharp){{ ref class MyClass{ public: property int Value; }; }} setアクセサ、getアクセサに別々のアクセスレベルを指定することも可能です。 #highlight(csharp){{ ref class MyClass{ private: int value; public: property int Value { public : int get(void) { return value; } private : void set(int value) { value = value; } } }; }} **インターフェイス インターフェイスにはメソッド、プロパティ、イベントを含むことが出来ます。 インターフェイスを宣言する場合は、interface class インターフェイス名 と記述します。 インターフェイスを実装するクラスでは、メソッド、プロパティ、イベントの先頭にvirtualを記述します。 #highlight(csharp){{ using namespace System; //インターフェイスの宣言 interface class IMyInterface { public: void myFunction(); property Object^ MyProperty; event EventHandler^ MyEvent; }; //インターフェイスを実装するクラス ref class MyClass : IMyInterface { public: virtual void myFunction() { } virtual property Object^ MyProperty; virtual event EventHandler^ MyEvent; }; }}