1. ホーム
  2. c++

[解決済み] フリー関数が期待されるメンバ関数を渡すにはどうしたらよいですか?

2022-04-28 23:34:13

質問

次のような問題です:このコードの一部を考えてみてください。

#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?
}

を使用するにはどうすればよいですか? a 's aClass::test を引数として function1 ? クラスのメンバにアクセスしたいのですが。

どのように解決するのですか?

関数ポインタを使うことは悪いことではありません。しかし、非静的メンバ関数へのポインタは、通常の関数ポインタとは異なります。メンバ関数は、関数への暗黙の引数として渡されるオブジェクト上で呼び出される必要があります。上のメンバ関数のシグネチャは、次のようになります。

void (aClass::*)(int, int)

を使おうとするタイプではなく

void (*)(int, int)

一つのアプローチとして、メンバー関数 static この場合、呼び出されるオブジェクトは必要なく、このオブジェクトを void (*)(int, int) .

クラスの非静的メンバにアクセスする必要がある場合 関数がC言語のインターフェイスの一部である場合など、 関数ポインタにこだわる必要がある場合は、常に void* からオブジェクトを取得する転送関数を通してメンバを呼び出します。 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);
}