ちょっとした質問があります。
C++ の動作はC#function Pointer
と似ていますか?delegate
はい、似ています。
ただし、C++ の関数ポインターはクラスのインスタンス メソッドを指すことはできませんが、C# のデリゲートは可能です。
.NET デリゲートは状態を持つことができます。つまり、オブジェクトのインスタンス メソッドへのデリゲートを作成し、デリゲートthis
内に保存することができます。
Foo f;
BarDelegate d = f.Bar;
d(); // stores f as 'this' pointer.
関数ポインターは、非メンバー関数を指す場合、デリゲートと同じ使用法を持ちます。軽量であるため (割り当てが不要)、実際にはデリゲートよりも優れていると言えます。
ただし、関数ポインターには状態がありません。これにより、メンバー関数で使用する場合に大きく異なりthis
ます。関数ポインターを呼び出すときに渡す必要があります。
Foo f;
BarPtr p = &Foo::Bar;
(f.*p)(); // need to pass in 'this' pointer. ugly call syntax!
C++ には「ファンクター」もあります。これは、状態を持つことができ、関数のように呼び出すことができるオブジェクトです。これは、テンプレート化された関数を呼び出すときにデリゲートの代わりに最もよく使用されます。しかし、ファンクタは単なる型の概念であり、実際の型ではありません:
struct BarFunctor
{
void operator()();
};
BarFunctor f;
f(); // not even a pointer, it's a full object and you're calling it.
.NET デリゲートの機能を正確に複製するためのより適切な比較は、C++ のstd::function
である可能性があります。これは、特定の呼び出しシグネチャで他のファンクターをラップできるファンクターです。ただし、std::function
デリゲートのようにオーバーヘッドがあり、テンプレートによってそのような重いオブジェクトが不要になることが多いため、あまり使用されません。
Foo f;
std::function<void()> func = [&] { f.Bar(); }; // the lambda object (a
func(); // functor) capturing a
// reference to f is
// stored into func (also
// a functor).
基本的にはそうですが、デリゲートの方がはるかに豊富です。関数ポインタは、関数が存在するメモリへの単なるポインタです。デリゲートは、関数ポインターを他の情報と共にラップするクラスです。
C# では基本的にすべてがクラスであるため、デリゲートはクラスのメソッドを指すことができます。C++ では、C++ 関数は特別な呼び出し規則を使用してクラス メソッドを呼び出し、関数ポインター自体はオブジェクトへのポインターを格納しないため、これは非常に苦痛です (それを個別に維持する必要があります)。
デリゲートはチェーン化することもでき、C++ 関数ポインターよりも型の柔軟性が高くなります。デリゲートの共分散と反分散を参照してください
そうです、C# のデリゲートは、関数ポインターを処理するクラス型です。また、関数ポインタは、問題の関数が存在するメモリ内の特定の場所を指す 32 ビットまたは 64 ビットの符号なし整数です。C++ では、生のアンマネージ関数ポインターしかありません。