関数ポインターを使用しても問題はありません。ただし、非静的メンバー関数へのポインターは、通常の関数ポインターとは異なります。メンバー関数は、暗黙の引数として関数に渡されるオブジェクトで呼び出す必要があります。したがって、上記のメンバー関数の署名は次のとおりです。
void (aClass::*)(int, int)
使用しようとするタイプではなく
void (*)(int, int)
1 つのアプローチは、メンバー関数を作成することで構成できますstatic
。この場合、オブジェクトを呼び出す必要はなく、 type で使用できますvoid (*)(int, int)
。
クラスの非静的メンバーにアクセスする必要が あり、たとえば関数が C インターフェースの一部であるなどの理由で関数ポインターに固執する必要がある場合、最善のオプションは、常に avoid*
を関数ポインターを取って関数に渡し、呼び出すことです。からオブジェクトを取得しvoid*
、メンバー関数を呼び出す転送関数を介してメンバー。
適切な C++ インターフェイスでは、関数オブジェクトが任意のクラス型を使用するためにテンプレート化された引数を関数に持たせることを検討したい場合があります。テンプレート化されたインターフェースを使用することが望ましくない場合は、次のようなものを使用する必要があります。std::function<void(int, int)>
これらに対して適切に呼び出し可能な関数オブジェクトを作成できますstd::bind()
。
クラス型または適切なテンプレート引数を使用する型安全なアプローチは、間違った型へのキャストによるエラーの可能性を排除するため、インターフェイスをstd::function<...>
使用するよりも望ましい方法です。void*
関数ポインターを使用してメンバー関数を呼び出す方法を明確にするために、次の例を示します。
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, nullptr);
foo object;
somefunction(&forwarder, &object);
}