155

問題は次のとおりです。次のコードを検討してください。

#include <iostream>


class aClass
{
public:
    void aTest(int a, int b)
    {
        printf("%d + %d = %d", a, b, a + b);
    }
};

void function1(void (*function)(int, int))
{
    function(1, 1);
}

void test(int a,int b)
{
    printf("%d - %d = %d", a , b , a - b);
}

int main()
{
    aClass a;

    function1(&test);
    function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
}

aaClass::test引数としてを使用するにはどうすればよいfunction1ですか? クラスのメンバーにアクセスしたいと思います。

4

9 に答える 9

166

関数ポインターを使用しても問題はありません。ただし、非静的メンバー関数へのポインターは、通常の関数ポインターとは異なります。メンバー関数は、暗黙の引数として関数に渡されるオブジェクトで呼び出す必要があります。したがって、上記のメンバー関数の署名は次のとおりです。

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);
}
于 2012-09-30T16:36:51.903 に答える
116

@Pete Beckerの答えは問題ありませんが、C++11でclassインスタンスを明示的なパラメーターとして渡さなくても実行できます。function1

#include <functional>
using namespace std::placeholders;

void function1(std::function<void(int, int)> fun)
{
    fun(1, 1);
}

int main (int argc, const char * argv[])
{
   ...

   aClass a;
   auto fp = std::bind(&aClass::test, a, _1, _2);
   function1(fp);

   return 0;
}
于 2012-09-30T16:42:26.370 に答える
59

メンバー関数へのポインターは、関数へのポインターとは異なります。ポインターを介してメンバー関数を使用するには、それへのポインター (明らかに ) とそれを適用するオブジェクトが必要です。したがって、適切なバージョンは次のfunction1ようになります

void function1(void (aClass::*function)(int, int), aClass& a) {
    (a.*function)(1, 1);
}

そしてそれを呼び出す:

aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
于 2012-09-30T16:35:18.813 に答える
0

メンバー関数を静的に作成し、すべてが機能します。

#include <iostream>

class aClass
{
public:
    static void aTest(int a, int b)
    {
        printf("%d + %d = %d\n", a, b, a + b);
    }
};

void function1(int a,int b,void function(int, int))
{
    function(a, b);
}

void test(int a,int b)
{
    printf("%d - %d = %d\n", a , b , a - b);
}

int main (int argc, const char* argv[])
{
    aClass a;

    function1(10,12,test);
    function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?

    getchar();return 0;
}
于 2018-12-15T12:12:11.310 に答える