Visual Studio 2017 を使用することをお勧めします

方法: デリゲートを定義および使用する (C++/CLI)

 

公開日: 2016年7月

Visual Studio 2017 RC の最新のドキュメントの詳細については、Visual Studio 2017 RC ドキュメントをご参照ください。

ここでは C++/CLIのデリゲートを定義して使用する方法を示します。

.NET Framework の一部のデリゲートを提供しますが、この新しいデリゲートを定義する必要があります。

次のコード例は MyCallbackという名前のデリゲートを定義します。 この新しいデリゲートがあるときに呼び出されるイベント処理コードは void 関数の戻り値の型を持つと String の参照を受け取る発生する必要があります。

main 関数は MyCallback のデリゲートをインスタンス化するに SomeClass で定義された静的メソッドを使用します。 デリゲートは、文字列内の単一します。「送出してデリゲート オブジェクト」に示すように、この関数を呼び出す別の方法です。 MyCallback の次の追加、インスタンスはリンクされ、デリゲート オブジェクトへの 1 回の呼び出しで実行されます。

// use_delegate.cpp  
// compile with: /clr  
using namespace System;  
  
ref class SomeClass  
{  
public:  
   static void Func(String^ str)  
   {  
      Console::WriteLine("static SomeClass::Func - {0}", str);  
   }  
};  
  
ref class OtherClass  
{  
public:  
   OtherClass( Int32 n )   
   {  
      num = n;  
   }  
  
   void Method(String^ str)   
   {  
      Console::WriteLine("OtherClass::Method - {0}, num = {1}",   
         str, num);  
   }  
  
   Int32 num;  
};  
  
delegate void MyCallback(String^ str);  
  
int main( )   
{  
   MyCallback^ callback = gcnew MyCallback(SomeClass::Func);     
   callback("single");   
  
   callback += gcnew MyCallback(SomeClass::Func);     
  
   OtherClass^ f = gcnew OtherClass(99);  
   callback += gcnew MyCallback(f, &OtherClass::Method);  
  
   f = gcnew OtherClass(100);  
   callback += gcnew MyCallback(f, &OtherClass::Method);  
  
   callback("chained");  
  
   return 0;  
}  

出力

静的な SomeClass::Func - Single
チェーンされた静的な SomeClass::Func -
チェーンされた静的な SomeClass::Func -
チェーンされた OtherClass::Method -数字 = 99
チェーンされた OtherClass::Method -数字 = 100 次のコード サンプルは、値クラスのメンバーとデリゲートを関連付ける方法を示します。

// mcppv2_del_mem_value_class.cpp  
// compile with: /clr  
using namespace System;  
public delegate void MyDel();  
  
value class A {  
public:  
   void func1() {  
      Console::WriteLine("test");  
   }  
};  
  
int main() {  
   A a;  
   A^ ah = a;  
   MyDel^ f = gcnew MyDel(a, &A::func1);   // implicit box of a  
   f();  
   MyDel^ f2 = gcnew MyDel(ah, &A::func1);  
   f2();  
}  

出力

テスト
テスト

構成されたデリゲートから構成するデリゲートを削除するには、「-」演算子を使用できます。

// mcppv2_compose_delegates.cpp  
// compile with: /clr  
using namespace System;  
  
delegate void MyDelegate(String ^ s);  
  
ref class MyClass {  
public:  
   static void Hello(String ^ s) {  
      Console::WriteLine("Hello, {0}!", s);  
   }  
  
   static void Goodbye(String ^ s) {  
      Console::WriteLine("  Goodbye, {0}!", s);  
   }  
};  
  
int main() {  
  
   MyDelegate ^ a = gcnew MyDelegate(MyClass::Hello);  
   MyDelegate ^ b = gcnew MyDelegate(MyClass::Goodbye);  
   MyDelegate ^ c = a + b;  
   MyDelegate ^ d = c - a;  
  
   Console::WriteLine("Invoking delegate a:");  
   a("A");  
   Console::WriteLine("Invoking delegate b:");  
   b("B");  
   Console::WriteLine("Invoking delegate c:");  
   c("C");  
   Console::WriteLine("Invoking delegate d:");  
   d("D");  
}  

出力

デリゲートの呼び出し a:
Hello!、A
デリゲートの呼び出し b:
goodbye、B!
デリゲートの呼び出し: c
Hello!、C
goodbye、C!
d:デリゲートの呼び出し
goodbye、D!

マネージ コンポーネントからネイティブ関数がマネージ コンポーネントのデリゲートのメンバー関数を呼び出すことができる関数ポインター パラメーターのネイティブ関数を呼び出すことができます。

次の例は、ネイティブ関数をエクスポートする .dll を作成する:

// delegate_to_native_function.cpp  
// compile with: /LD  
#include < windows.h >  
extern "C" {  
   __declspec(dllexport)  
   void nativeFunction(void (CALLBACK *mgdFunc)(const char* str)) {  
      mgdFunc("Call to Managed Function");  
   }  
}  

次の例は、.dll を使用し、関数ポインターを要求するネイティブ関数にデリゲートのハンドルを渡します。

// delegate_to_native_function_2.cpp  
// compile with: /clr  
using namespace System;  
using namespace System::Runtime::InteropServices;  
  
delegate void Del(String ^s);  
public ref class A {  
public:  
   void delMember(String ^s) {  
      Console::WriteLine(s);  
   }  
};  
  
[DllImportAttribute("delegate_to_native_function", CharSet=CharSet::Ansi)]  
extern "C" void nativeFunction(Del ^d);  
  
int main() {  
   A ^a = gcnew A;  
   Del ^d = gcnew Del(a, &A::delMember);  
   nativeFunction(d);   // Call to native function  
}  

出力

マネージ関数の呼び出し

ネイティブ関数にデリゲートを関連付けるには、マネージ型のネイティブ関数をラップし、関数が PInvokeで呼び出されると宣言する必要があります。

// mcppv2_del_to_umnangd_func.cpp  
// compile with: /clr  
#pragma unmanaged  
extern "C" void printf(const char*, ...);  
class A {  
public:  
   static void func(char* s) {  
      printf(s);  
   }  
};  
  
#pragma managed  
public delegate void func(char*);   
  
ref class B {  
   A* ap;  
  
public:  
   B(A* ap):ap(ap) {}  
   void func(char* s) {  
      ap->func(s);   
   }  
};  
  
int main() {  
   A* a = new A;  
   B^ b = gcnew B(a);  
   func^ f = gcnew func(b, &B::func);  
   f("hello");  
   delete a;  
}  

出力

hello

デリゲートが呼び出されると、関数を呼び出してする型のインスタンスを渡すために非バインドのデリゲートを使用できます。

自由なデリゲートは for each、in コレクションを使用して a オブジェクトを反復処理しキーワードと、各インスタンスのメンバー関数を呼び出す場合に特に便利です。

ここで境界と自由なデリゲートを宣言し、インスタンス化し、呼び出す方法をです:

アクションバインドされたなデリゲート自由なデリゲート
Declareデリゲートのシグネチャは、デリゲートを使用して、呼び出そうとしている関数のシグネチャと一致する必要があります。デリゲートのシグネチャの最初のパラメーターは、呼び出す対象のオブジェクトの this の種類です。

最初のパラメーターの後ろに、デリゲートのシグネチャは、デリゲートを使用して、呼び出そうとしている関数のシグネチャと一致する必要があります。
Instantiateバインドされたなデリゲートをインスタンス化すると、インスタンスの関数またはグローバルまたはスタティック メンバー関数を指定できます。

インスタンス関数を指定するには、最初のパラメーターは、メンバー関数を呼び出してたい、2 番目のパラメーターは、呼び出しの対象となる関数のアドレスの型のインスタンスです。

グローバル変数または静的メンバー関数を呼び出すときには、グローバル関数の名前または静的メンバー関数の名前を渡します。
非バインドのデリゲートをインスタンス化するとき、呼び出す対象の関数のアドレスを渡します。
Callバインドされたなデリゲートを呼び出すと、デリゲートのシグネチャに必要なパラメーターを渡します。最初のパラメーターは、呼び出しの対象となる関数を含むオブジェクトのインスタンスであることをバインドされたなデリゲートと同様ですが、保存されています。

このサンプルでは、自由なデリゲートを宣言し、インスタンス化し、呼び出す方法を説明します:

// unbound_delegates.cpp  
// compile with: /clr  
ref struct A {  
   A(){}  
   A(int i) : m_i(i) {}  
   void Print(int i) { System::Console::WriteLine(m_i + i);}  
  
private:  
   int m_i;  
};  
  
value struct V {  
   void Print() { System::Console::WriteLine(m_i);}  
   int m_i;  
};  
  
delegate void Delegate1(A^, int i);  
delegate void Delegate2(A%, int i);  
  
delegate void Delegate3(interior_ptr<V>);  
delegate void Delegate4(V%);  
  
delegate void Delegate5(int i);  
delegate void Delegate6();  
  
int main() {  
   A^ a1 = gcnew A(1);  
   A% a2 = *gcnew A(2);  
  
   Delegate1 ^ Unbound_Delegate1 = gcnew Delegate1(&A::Print);  
   // delegate takes a handle  
   Unbound_Delegate1(a1, 1);  
   Unbound_Delegate1(%a2, 1);  
  
   Delegate2 ^ Unbound_Delegate2 = gcnew Delegate2(&A::Print);  
   // delegate takes a tracking reference (must deference the handle)  
   Unbound_Delegate2(*a1, 1);  
   Unbound_Delegate2(a2, 1);  
  
   // instantiate a bound delegate to an instance member function  
   Delegate5 ^ Bound_Del = gcnew Delegate5(a1, &A::Print);  
   Bound_Del(1);  
  
   // instantiate value types  
   V v1 = {7};  
   V v2 = {8};  
  
   Delegate3 ^ Unbound_Delegate3 = gcnew Delegate3(&V::Print);  
   Unbound_Delegate3(&v1);  
   Unbound_Delegate3(&v2);  
  
   Delegate4 ^ Unbound_Delegate4 = gcnew Delegate4(&V::Print);  
   Unbound_Delegate4(v1);  
   Unbound_Delegate4(v2);  
  
   Delegate6 ^ Bound_Delegate3 = gcnew Delegate6(v1, &V::Print);  
   Bound_Delegate3();  
}  

出力

2
3
2
3
2
7
8
7
8
7 次の例は、自由なデリゲートおよびコレクション オブジェクトを反復処理したり各インスタンスのメンバー関数を呼び出すに for each、in キーワードを使用する方法を示します。

// unbound_delegates_2.cpp  
// compile with: /clr  
using namespace System;  
  
ref class RefClass {  
   String^ _Str;  
  
public:  
   RefClass( String^ str ) : _Str( str ) {}  
   void Print() { Console::Write( _Str ); }  
};  
  
delegate void PrintDelegate( RefClass^ );  
  
int main() {  
   PrintDelegate^ d = gcnew PrintDelegate( &RefClass::Print );  
  
   array< RefClass^ >^ a = gcnew array<RefClass^>( 10 );  
  
   for ( int i = 0; i < a->Length; ++i )  
      a[i] = gcnew RefClass( i.ToString() );  
  
   for each ( RefClass^ R in a )  
      d( R );  
  
   Console::WriteLine();  
}  

このサンプルでは、プロパティのアクセサーに非バインドのデリゲートを作成する:

// unbound_delegates_3.cpp  
// compile with: /clr  
ref struct B {  
   property int P1 {  
      int get() { return m_i; }  
      void set(int i) { m_i = i; }  
   }  
  
private:  
   int m_i;  
};  
  
delegate void DelBSet(B^, int);  
delegate int DelBGet(B^);  
  
int main() {  
   B^ b = gcnew B;  
  
   DelBSet^ delBSet = gcnew DelBSet(&B::P1::set);  
   delBSet(b, 11);  
  
   DelBGet^ delBGet = gcnew DelBGet(&B::P1::get);     
   System::Console::WriteLine(delBGet(b));  
}  

出力

11 次の例は、1 種類のインスタンスがバインドされたである 1 のインスタンスがバインドされたマルチキャスト デリゲートを呼び出す方法を示します。

// unbound_delegates_4.cpp  
// compile with: /clr  
ref class R {  
public:  
   R(int i) : m_i(i) {}  
  
   void f(R ^ r) {  
      System::Console::WriteLine("in f(R ^ r)");  
   }  
  
   void f() {  
      System::Console::WriteLine("in f()");  
   }  
  
private:  
   int m_i;  
};  
  
delegate void Del(R ^);  
  
int main() {  
   R ^r1 = gcnew R(11);  
   R ^r2 = gcnew R(12);  
  
   Del^ d = gcnew Del(r1, &R::f);  
   d += gcnew Del(&R::f);  
   d(r2);  
};  

出力

f (r) ^ R
f() 次の例は、無料の汎用デリゲートを作成して照会する方法を示します。

// unbound_delegates_5.cpp  
// compile with: /clr  
ref struct R {  
   R(int i) : m_i(i) {}  
  
   int f(R ^) { return 999; }  
   int f() { return m_i + 5; }  
  
   int m_i;  
};  
  
value struct V {  
   int f(V%) { return 999; }  
   int f() { return m_i + 5; }   
  
   int m_i;  
};  
  
generic <typename T>  
delegate int Del(T t);  
  
generic <typename T>  
delegate int DelV(T% t);  
  
int main() {     
   R^ hr = gcnew R(7);  
   System::Console::WriteLine((gcnew Del<R^>(&R::f))(hr));  
  
   V v;  
   v.m_i = 9;  
   System::Console::WriteLine((gcnew DelV<V >(&V::f))(v) );  
}  

出力

12
14

delegate

表示: