Я читал о делегировании и хотел иметь возможность вызывать внутри базового класса любую функцию, передаваемую в качестве параметра в зависимости от события, поэтому, если, например, у меня есть объект синтаксического анализа, и я хочу назначить какой метод из другого объекта вызывать в зависимости от того, что токен найден. Я сделал, как показано ниже, это работает, но я не уверен, что это правильный путь, или это портативно, как тоже.
class base{
public:
typedef void (base::*methodPTR)();
methodPTR pfn;
void setMethod(methodPTR fn)
{
pfn = fn;
}
void run(){
if(pfn) (this->*pfn)();
}
};
class a : public base {
public:
};
class b : public base
{
a ob;
public:
void init()
{
//this function fn is not define neither in object "a" or "base"//but still I can assign arbitrary member function just like I wanted
ob.setMethod(static_cast<base::methodPTR>(&b::fn));
}
void fn()
{
cout << "from class b!" << endl;
}
void test()
{
ob.run();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
b x;
x.init();
x.test();
return 0;
}
Делать то, что вы делаете, безопасно, если вы уверены, что никогда не вызовете указатель члена на объект, который на самом деле не относится к одному из типов, из которых поступил указатель (то есть вы не вызываете a::x
на base
).
Попробуйте шаблонное решение для этой проблемы, в этом примере я уверен в использовании правильных объектов для вызова правильных функций.
Мы могли бы использовать это в случае, когда у нас есть объекты карты и обратные вызовы, и мы можем вызывать их в зависимости от некоторых условий.
//store objects vs callbacks
//you could replace int in map with some condition or key to invoke a callback
#include <iostream>
#include <map>
using namespace std;
template<class T>
class A {
protected:
void (T::*curr_f)();
private:
static std::map<int, std::map<T*,void (T::*)() > > callBacks;
public:
virtual void set(void (T::*f)()) {
curr_f = f;
cout<<"Set in A"<<endl;
T* obj = new T();
static int x = 0;
callBacks[++x][obj] = f;
// (obj->*curr_f)();
}
virtual void new_function() {cout<<"in A"<<endl;};
static void run()
{
for(typename std::map<int,std::map<T*,void (T::*)() > >::iterator itr = A<T>::callBacks.begin();
itr != A<T>::callBacks.end(); ++itr)
{
for(typename std::map<T*,void (T::*)() >::iterator itr2 = itr->second.begin();
itr2 != itr->second.end(); ++itr2)
{
((itr2->first)->*(itr2->second))();
}
}
}
};
template<class T>
std::map<int, std::map<T*,void (T::*)() > > A<T>::callBacks;
class B :public A<B> {
public:
void func() {
set(&B::new_function);
};
void new_function() {cout<<"in B"<<endl;};
};
class C:public A<C> {
public:
void func() {
set(&C::new_function);
};
void new_function() {cout<<"in C"<<endl;};
};
int main()
{
B obj1;
C obj2;
obj1.func();
obj2.func();
A<B>::run();
A<C>::run();
}