任意のクラス (読み取り: 特定のクラスではない) のメンバー関数を指すことができる関数ポインター (非 C++ 11) を宣言することは可能ですか?
たとえば、クラス A、B、および C があるとします。C には関数ポインターが宣言されており、そのポインターを B のメンバー関数の 1 つと A のメンバー関数の 1 つを指すように切り替えたいとします。C++ はこれを許可しますか?
任意のクラス (読み取り: 特定のクラスではない) のメンバー関数を指すことができる関数ポインター (非 C++ 11) を宣言することは可能ですか?
たとえば、クラス A、B、および C があるとします。C には関数ポインターが宣言されており、そのポインターを B のメンバー関数の 1 つと A のメンバー関数の 1 つを指すように切り替えたいとします。C++ はこれを許可しますか?
はい、できますが、タイプ セーフを削除し、 thisポインターとメンバー関数を追跡する必要があります。
http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegatesでユースケースを確認できます。基本的な考え方は、オブジェクト ポインターを void ポインターとして格納し、静的メソッドを介して関数呼び出しをリダイレクトすることです。
#include <iostream>
using namespace std;
struct A { void foo() { cout << "A::foo\n"; } };
struct B { void foo() { cout << "B::foo\n"; } };
class C
{
public:
C() : object_ptr(0), stub_ptr(0) {}
template <class T, void (T::*TMethod)()>
static C from_method(T* object_ptr)
{
C d;
d.object_ptr = object_ptr;
d.stub_ptr = &method_stub<T, TMethod>;
return d;
}
void operator()() const
{
return (*stub_ptr)(object_ptr);
}
private:
typedef void (*stub_type)(void* object_ptr);
void* object_ptr;
stub_type stub_ptr;
template <class T, void (T::*TMethod)()>
static void method_stub(void* object_ptr)
{
T* p = static_cast<T*>(object_ptr);
return (p->*TMethod)();
}
};
int main()
{
A a;
B b;
C c = C::from_method<A, &A::foo>(&a);
c();
c = C::from_method<B, &B::foo>(&b);
c();
return 0;
}
上記のコードが出力されるはずです
A::foo
B::foo
このソリューションはstd::function
、データ用にヒープに割り当てられたストレージを必要としないため、使用するよりも高速ですが、これはメンバー関数を参照するためにのみ使用できます (std::function
呼び出し可能なオブジェクトの所有権を主張するのとは異なります)。
boost::function
と一緒にこれを行うことができますboost::bind
:
#incluce <boost/function.hpp>
#include <boost/bind.hpp>
struct A{ void f(); };
struct B{ void g(); };
struct C{
boost::function<void()> _func;
};
int main(){
A a; B b; C c;
c.func = boost::bind(&A::f, &a);
c.func();
c.func = boost::bind(&B::g, &b);
c.func();
}
不可能です。クラスのメンバー関数を宣言すると、その関数には暗黙のthis
パラメーターがあるため、を記述してもvoid A::func(int i)
、関数には実際には次のシグネチャがあります。
void func(A *const this, int i)
Boost.FunctionとBoost.Bindのような何かを一緒に使用して、達成したいことを実行する必要があります。
boost::function<void (int)> func;
A* a = new A;
func = boost::bind(&A::func, a, _1);
いいえ。ただし、AとBに共通のベースクラスXを設定してから、AとBの両方に使用できますT (X::*)(U...)
(TとUが同じであると仮定)。
または、単にを使用することもできますboost::variant
。
いいえ、できません。
そして、できればそれは意味がありません。少し想像してみてください。タイプAのオブジェクトがあり、タイプBのメンバー関数を指すメンバー関数ポインターを呼び出します。突然、Bのメンバー関数に、アドレスを指すこのポインターがあります。 Aオブジェクトの、しかしタイプがB*
。
それはあなたが解決しようとしている本当の問題が何であるかによって異なります(多分あなたはそれについて尋ねるべきでした)が、あなたはすべてのクラスに共通の基本関数(多分仮想)を持たせてそれらへのポインタを使うようにすることができます、しかしあなたが私たちに提供しない限りより詳細に、私たちは推測することしかできませんでした。
もう1つのより広範な代替手段はboost::function
、メンバー関数を呼び出したいオブジェクトにすでに関連付けられているオブジェクトを使用することです。