3

クラスと関数があるとします

class A
{
    int a;
    int b;
    int mul()
    {
        return a+b;
    }
};
...

void func(int af, int bf, int (*fc)())
{
    ...
}

メイン関数では、関数はクラス A のメソッドを使用することになっています

int main
{
    A as;
    ...
    func(as.a, as.b, as.mul);
}

ただし、それはできません。コンパイラは、合格していると言い続けます

(int&, int&, 'unresolved overloaded function type') 

候補の関数に

(int, int, void(*)()).

それはなぜですか、またクラスのメソッドを別の関数に渡す方法は?

ああ、問題をもう少し明確にする必要があると思います。func(...)実際には、私が取り組んでいるアルゴリズムの関数です。そしてclass A、アルゴリズムを使用してシミュレーションを行うモデルです。したがって、関数 B で A のインスタンスを具体的に使用するとは思いませんが、A のメソッドとコンポーネントのみを渡し、それらを操作します。


更新: クラス A で静的メソッドを使用することについて言及している人もいますが、これはまだ部分的な解決策です。静的メソッドmul()を使用すると、a と b の両方が静的であると主張せざるを得なくなります。また、A の複数のインスタンスを使用する必要があり、メイン関数の各インスタンスでメソッド a、b が異なる場合、静的変数の使用は単純に失敗します。

それで、静的変数/メソッドを使用せずにこれを修正する方法について他の提案はありますか? Python などのスクリプト言語では、どのような型のメソッドを渡しても基本的には問題にならなかったことを覚えています。C++ で同様のことができないのはなぜですか? または、これを行うのに役立つ C++ の回避策はありますか?

4

5 に答える 5

5

まず、mulは のメンバー関数Aあるため、グローバル関数またはメンバー関数であるかのように呼び出すことはできませんstatic。関数が呼び出されるオブジェクトが必要です。

A::mul(); // ERROR!
A a;
a.mul(); // OK

つまり、 の定義を変更して、メンバー関数へのポインターを受け入れることができます。func

void func(int af, int bf, void (A::*fc)())
//                        ^^^^^^^^^^^^^^^

ただし、メンバー関数を呼び出す具体的なインスタンスをまだ渡していないため、この変更だけではあまり進歩しません。Aつまり、これは違法になります。

fc(); // ERROR!

Aこの制限を克服するには、参照またはポインターをtogetherのインスタンスに渡し、以下のfuncように呼び出すことができます。

void func(A* pA, int af, int bf, void (A::*fc)())
{
    ...
    (pA->*func)();
}

ただし、func()メンバー関数を呼び出すオブジェクトが引数として渡される場合、afandの目的が明確ではありませんbf

おそらく、mul()メンバー関数が の具体的なインスタンスで動作する必要がなくA、それでも のメンバーにしたい場合は、次のAように宣言できますstatic

class A
{
    int a;
    int b;
    static void mul();
//  ^^^^^^
};

これにより、元の呼び出しがfunc()コンパイルされます。ただし、この場合、引数を受け入れないという事実は、呼び出されたオブジェクトのおよびメンバーでmul()動作することになっていることを示唆しているため、これが意味をなすかどうかは明確ではありません。ab

于 2013-03-28T17:50:12.547 に答える
1

やりたいことは、メンバー関数ポインター ( ) をインスタンス ( ) 自体A::mulと共に渡すことです。a追加のコードがなければ、これはそれほど簡単ではありません。

メンバー関数ポインターはインスタンスに結び付けられていません (呼び出し先のインスタンスではなく、関数自体のみを表します)。それらのタイプは、クラス名とともに記述されます。Aあなたの署名を持つメンバー関数ポインターの型は次のfuncようになります。

void (A::*)()     // The type only, anonymous
void (A::*fc)()   // An actual function pointer with the name `fc`

このような関数を呼び出すには、次の構文を使用する必要があります。ご覧のとおり、関数を呼び出すインスタンスが関与している必要があります。

(a->*fc)();       // If a is of type A*
(a.*fc)();        // If a is of type A or A&

まとめると、基本的に 2 つのオプションがあります。

  1. また、メンバー関数ポインターに加えて、インスタンスを (ポインター、const または変更可能な参照として) 渡します。次に、そのインスタンスでメンバー関数ポインターを呼び出します。

    あなたは関数の署名であり、実装は次のようになります。

    void func(int af, int bf, void (A::*fc)(), A *a) {
        // When you want to call the function fc on a:
        (a->*fc)();
    }
    

    を呼び出すfuncには、次のようなコードを使用します。

    func(as.a, as.b, &A::mul, a);
    
  2. インスタンスと一緒にメンバ関数ポインタをそのまま呼び出せるファンクタに変換します。これは とstd::mem_fn一緒に行うのが最適std::bind1stです。

    あなたは関数の署名であり、実装は次のようになります。

    void func(int af, int bf, std::function<void()> fc) {
        // When you want to call the function fc:
        fc();
    }
    

    を呼び出すfuncには、次のようなコードを使用します。

    func(as.a, as.b, std::bind1st(std::mem_fn(&A::mul), a));
    
于 2013-03-28T17:49:52.400 に答える
1

mul非静的メンバーであることが意図されており、それAを呼び出すタイプのオブジェクトが必要ですか? その場合、メンバーへのポインターを渡す必要があります。

void func(int af, int bf, void (A::*fc)())
{ //                            ^^^  
    A a = whatever();
    (a.*fc)();
}

オブジェクトなしで呼び出すことを意図している場合は、 にする必要がありますstatic

于 2013-03-28T17:52:06.623 に答える
1

leemes が言ったように、std::functionこれは私が推奨する方法でも実行できますが、コンパイラがサポートしているものを確認してくださいstd::bind。以下の例は、Visual Studio 2012 で動作します (C++11 のフラグが有効になっている新しいバージョンの GCC で動作し、VS 2010 で動作する場合と動作しない場合があります)。

void func(int af, int bf, std::function<void()> fc)
{
    fc();
}

次のように呼び出します。

func(as.a, as.b, std::bind(&as::mul, &A));

の新しいバージョンは、メンバー関数が検出された場合にstd::bindその役割を果たします。std::mem_fcnここにリンクされているドキュメントを参照してください。

std::関数

std::bind

于 2013-03-28T18:37:28.703 に答える
1

int (*fc)(int,int)void別の例で指定された return および空のパラメータ リスト)を通常の関数ポインタ(クラス メンバ関数への関数ポインタではないことを意味します)として本当に扱いたい場合は、次のようにして の関数を使用しAて に渡すことができfuncます。mulポイントは、静的メンバー関数として宣言することです。乗算のような非常に単純な操作を想定しています。

#include <iostream>
class A
{
public: //necessary otherwise not accessible in main
   int a;
   int b;
   A(int p1, int p2):a(p1),b(p2){} //assume you need to somehow pass a,b into mul
   static int mul(int p1, int p2)  {return p1*p2;};  //mul should be static
};

void func(int af, int bf, int (*fc)(int,int))  
//using void still work but you need to change declaration of mul in A
{
  int res = fc(af,bf);  
  cout << res <<endl;
}

int main()
{
  A as(2,4);
  func(as.a, as.b, &A::mul); //call A::mul, use as regular function pointer, output 8
  func(10,10, &A::mul); //will output 100
  return 0;
}

このようにして、通常の関数ポインターが指すことができる A の静的メンバー関数を使用しています。aクラスとして、またクラス内ではもう何の関係もありbません。

于 2013-03-28T18:18:41.987 に答える