-1

I have a class which should hold a pointer to methods of various classes and call them via it.

Something like here but with a small -or maybe not- difference. Those various other methods are not overloaded.
Example:

Derived1 d1;    
OtherClass* handlerInst = new OtherClass();
handlerInst->Add( &d1, &(Derived1::method1) );

In Add(...) I want to pass whatever member method of class types derived from base.
Is this possible somehow?

Edit:

The idea is that OtherClass is a thread(not standard c++ thread). Some code of other classes(Derived1, derived2...)-it is not mandatory to have a common base class- can thus must be run only after this thread has ended its run. I am hoping to see if i can add methods with whatever name. Also being a thread has nothing to do with this. It can be a simple class which when it ends its method it runs some code from other classes.

Community
  • 1
  • 1
0gap
  • 21
  • 7
  • If you mean that these methods aren't overriden from the base class, then you'll need some type-erasure. Side note: I'm pretty sure the parentheses in `&(Derived::method1)` shouldn't be there, even if they are in the other question's code as well. – Quentin Aug 02 '16 at 10:53
  • Yes, this is possible, somehow. – Sam Varshavchik Aug 02 '16 at 10:58
  • Do all the methods you want to hold take the same parameter types? – ROX Aug 02 '16 at 11:56
  • @ROX let's say they have no arguments at all. – 0gap Aug 02 '16 at 12:41

2 Answers2

1

I'm assuming these functions also return the same type (I've gone with void in this example).

You don't say whether the functions are overrides of virtual functions declared in base - you mention they are not overloads, but if they are not overrides then the existence of base doesn't really help here.

If they do exist in base then you can try the following:

#include <vector>
class OtherClass 
{ 
    using FunctionPtrType = void(Base::*)();
    std::vector<std::pair<Base*, FunctionPtrType>> m_Collection;

   public:


   void Add(Base* object, FunctionPtrType pMemberFunction)
   {
       m_Collection.emplace_back(object, pMemberFunction);
    }

   void CallAll()
   {
       for(auto item : m_Collection)
       {
           (item.first->*item.second)();
       }
    }
};

calling example

Derived d1;
OtherClass holder;
holder.Add(&d1, &Base::Func);
holder.CallAll()

If on the other hand the functions do not override virtual functions in base, then I have another solution involving a wrapper class, which I can post if the above doesn't work for you.

ROX
  • 1,256
  • 8
  • 18
  • sorry for the late reply. I have implemented this though a bit simpler(i used a simple array of pointers to base class and later called the function which was common for all derived ones added). Yeah i was hopping to get an answer where the method names are different. Deriving from a base class is not mandatory. The method in the base class is pure virtual. The base class is used solely for the purpose of the derived ones to be added to OthersClass array/vector whatever. – 0gap Aug 24 '16 at 08:53
  • The above does allow different method names, providing they exist on the base class. e.g. OtherDervied d2; holder.Add(&d2, &Base::OtherFunc); – ROX Aug 24 '16 at 09:58
  • i will stay with this implementation and have to keep a common method in the base class to call from the derived ones. Thanks. – 0gap Aug 24 '16 at 10:34
0

You can store member functions bound to their instance, and use std::is_base_of to check if they are of correct type.

In the example below, each method is stored twice, so they'll be called twice, too.

// https://github.com/KubaO/stackoverflown/tree/master/questions/method-ptr-list-38718402
#include <cassert>
#include <vector>
#include <functional>
#include <type_traits>

struct Base {};
struct Derived : Base {
   int counter = 0;
   void method1() { counter += 10; }
   void method2() { counter += 100; }
};

template <typename B>
class HandlerList {
   using fun = std::function<void()>;
   std::vector<fun> m_handlers;
public:
   template <typename T,
             typename = typename std::enable_if<std::is_base_of<B, T>::value>::type>
   void add(T* instance, void(T::* member)()) {
      m_handlers.push_back(std::bind(member, instance));
   }
   template <typename T,
             typename = typename std::enable_if<std::is_base_of<B, T>::value>::type>
   void add(T* instance, std::initializer_list<void(T::*)()> members) {
      for (auto & member : members)
         add(instance, member);
   }
   void call() {
      for (auto const & handler : m_handlers)
         handler();
   }
};

int main()
{
   struct NotDerived { void foo() {} } nd;
   Derived d;
   HandlerList<Base> h;
   h.add(&d, &Derived::method1);
   h.add(&d, &Derived::method2);
   h.add(&d, { &Derived::method1, &Derived::method2 });
#if 0
   h.add(&nd, &NotDerived::foo); // this will fail to compile
#endif
   h.call();
   assert(d.counter == 220);
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313