2016-07-21 11 views
0

次のサンプルコードを使用して質問を説明します。クラススコープを避けて、メンバー関数を関数ポインタとして渡します。

私は次のように定義されたクラスBを持っている:

class B 
{ 
    public: 
     inline B(){} 
     inline B(int(*f)(int)) :myfunc{ f }{} 
     void setfunction(int (*f)(int x)) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     int(*myfunc)(int); 
}; 

次のように私は、クラスAの定義:

class A 
{ 
    public: 
    A(int myint) :a{ myint }{ b.setfunction(g); } 
    int g(int) { return a; } 
    void print() { b.print(a); } 

    private: 
    B b; 
    int a; 
    }; 

を私に問題がメンバ関数gが署名を持っていることのようですint A::g(int)int g(int)ではなく

上記の作業を行う標準的な方法はありますか?私は、いくつかの操作を実行するメンバ関数を含むクラス(クラスB)と、クラスの特定のメンバ関数を使用する必要があるクラス(クラスA)を持っているという点で、これはかなり一般的な設定だと思いますB - 私のデザインが間違っているのでしょうか?もしそうなら、このアイデアを表現する最良の方法は何ですか?

+0

はい、この関数 'static'を宣言。あるいは、インタフェースクラスを使用して、抽象関数 'virtual int g(int)= 0;'を定義します。このクラスから 'クラスA:公共クラス<クラス名> 'を派生させてください。次に、このクラスのインスタンスをクラス 'B'の関数に渡します。 –

+2

C++ 11/14にタグ付けしたので、ラムダで 'std :: function'を使用することをお勧めしますか?それはあなたに少しコストがかかりますが、良い方法はありません。 – user975989

+0

Google「メンバー関数ポインタC++」 –

答えて

3

あなたはSTDを使用することができます::機能:

class B 
{ 
public: 
    inline B() {} 
    inline B(std::function<int(int)> f) : myfunc{ f } {} 
    void setfunction(std::function<int(int)> f) { myfunc = f; } 
    void print(int number) { std::cout << myfunc(number) << std::endl; } 
private: 
    std::function<int(int)> myfunc; 
}; 

class A 
{ 
public: 
    A(int myint) :a{ myint } { 
    b.setfunction([this](int a) { 
     return g(a); 
    } 
    ); 
    } 
    int g(int) { return a; } 
    void print() { b.print(a); } 

private: 
    B b; 
    int a; 
}; 
+0

これは基本的な質問であれば助けてくれてありがとう、 std :: functionとlambdaについて多くのことを知っています。 (int a){return g(a)}は、 "定数関数" g(a)をラップしてint A::(int)という形式の関数に見せ、std: :関数はこれをさらに「剥ぎ取って」、それがint(int)になるようにします。なぜ[](int a){return g(a); } うまくいかない? –

+0

@DonShanil [] - lamba本体の中でどのシンボルが表示されるかを決定するキャプチャです.gはクラスのメンバ関数です。したがって、それを呼び出すには、[]にこれを渡して、可能にします。 – AnatolyS

1

使用std::functionstd::bind

class B 
{ 
    public: 
     inline B(int(*f)(int)) :myfunc{ f }{} 
     void setfunction(std::function<int(int)> f) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     std::function<int(int)> myfunc; 
}; 

// ... 
A a; 
B b(std::bind(&A::g, &a)); 

はまた、それ以外の場合は、値が定義されていないですが、あなたには、いくつかのデフォルト値(ほとんどの場合はnull)への関数ポインタを初期化し、使用している場合、それを確認する必要があることに注意してください。

+0

ありがとう、ありがとう。 –

2

クラスBを一般化することができます。ポインタ(int(*)(int))を保持する代わりに、私がintで呼び出すことができ、別のintを返すことが本当に必要なものです。 std::function<int(int)>:C++ 11には、まさにこの理由のために、型消去機能異議導入

class B 
{ 
    using F = std::function<int(int)> 
public: 
    B(){} 
    B(F f) : myfunc(std::move(f)) { } 
    void setfunction(F f) { myfunc = std::move(f); } 
    void print(int number) { std::cout << myfunc(number) << std::endl; } 
private: 
    F myfunc; 
}; 

をそしてあなただけのAからBに一般的な呼び出し可能を提供することができます。

A(int myint) 
: b([this](int a){ return g(a); }) 
, a{ myint } 
{ } 
+0

'std :: bind'にプレースホルダがないと思います。 – Holt

+1

@Holtなぜ私は決して 'bind()'を使わないのか思い出してくれてありがとう。 – Barry

+0

Thanks Barry!「intを呼び出して別のintを返すことができるもの」を理解しようとするだけで、なぜ標準関数はstd :: functionの型と見なされないのですか?たとえば、[this](int a)を[&](int a)に変更すると、すべてがうまくいきますが、[](int a)は許可されません。 –

1

あなたはメンバ関数A::gをバインドするstd::bindを使用することができます。

class B 
{ 
    public: 
     inline B(){} 
     inline B(std::function<int(int)> f) :myfunc{ f }{} 
     void setfunction(std::function<int(int)> f) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     std::function<int(int)> myfunc; 
}; 
class A 
{ 
    public: 
     A(int myint) :a{ myint } { 
      b.setfunction(std::bind(&A::g, this, std::placeholders::_1)); 
     } 
     int g(int) { return a; } 
     void print() { b.print(a); } 

    private: 
     B b; 
     int a; 
}; 

あなたはstd::bindで適用される、std::functionに関数ポインタからファンクタの種類を変更する必要があります。

LIVE

+0

ありがとう、ありがとう。 –

関連する問題