Solved

Pointer to a member function that isn't common

Posted on 2009-07-14
49
208 Views
Last Modified: 2012-05-07
Hello.

Strange title - apologies... perhaps the addition of a description field on questions would improve things slightly?

Anyways, yes, I have the code below (incomplete - obviously), which doesn't work simply for the reason that the second parameter to addEventListener is not declared as a member of CEventListener, now I could just add in an eventReceived method to the CEventListener class and override it, but that's not quite what I'm after as then there can only be one eventReceived method in any one class that derives from CEventListener. So, are there any tricks/tips/hacks of getting a pointer to a member function, of whose class will always be derived from CEventListener of which it is not a member and then calling it?

Hm, that's a bit of a mouthful that last sentence, hopefully those of you who are more skilled at English than us native speakers can decipher what I mean. ;)

Thank you,
Uni
/******************************************************************************************

This class contains no functionality of its own - in that respect it is useless. What it

is useful for though is to allow us to use member function pointers in the event sender. We

could use templates, but this would have the disadvantage that when we declare the

CEventSender, events could only be send to the class that was defined when we created the

object. So, any class derived from this class can then listen for events.

******************************************************************************************/

class CEventListener{

};//End class definition.
 
 

CEventSender{

	public:

		bool addEventListener(CEventListener *aEventListener, void (*aMemberFunction)()){

			return true;

		}

};
 

class CListener1:public CEventListener{

public:

	void eventReceived(){

		MessageBox(0, L"", L"", 0);

	}

};
 

int main(){

	CEventSender objEventSender1;

	CListener1 objListener1;

	objEventSender1.addEventListener(&objlistener1, &CListener1::listener1);	

	return 0;

}

Open in new window

0
Comment
Question by:Unimatrix_001
  • 24
  • 10
  • 8
  • +1
49 Comments
 
LVL 40

Expert Comment

by:evilrix
ID: 24854502
>> that's a bit of a mouthful that last sentence, hopefully those of you who are more skilled at English than us native speakers can decipher what I mean
Hmmm, that probably explains why I haven't a clue what you are trying to do :)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24854515
What if you make eventReceived a static method ? Does that solve your problem ?
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854550
>>Hmmm, that probably explains why I haven't a clue what you are trying to do :)
Everybody from the south knows northerners cannot talk! Hehehe. ;)

Well - essentially, I'm trying to take a pointer to a member function (eventReceived()), and the class which contains that method (CListener1) is derived from another class (CEventListener). But the issue is that the method which accepts the member function (addEventListener(...)), must accept any object which derives from CEventListener, although CEventListener doesn't actually contain the member function (eventReceived()) but derived classes do.... Hm, hope that helps...

>>What if you make eventReceived a static method ? Does that solve your problem ?
Sort of... I could make a static method in the class CListener1, which then passes it to the correct member function within its class, but I'm trying to find a way around that...

Thanks,
Uni
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24854554
No comprende, senor. :)

Actually a short in the dark, are you trying to allow derived classes to override a listener member function?
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854567
>>No comprende, senor. :)
Not to worry... Seems to be a recurring theme in my questions lately...

>>Actually a short in the dark, are you trying to allow derived classes to override a listener member function?
No, because then when we get a pointer to the CEventListener::eventRaised method, then I cannot have more than one eventRaised method within the derived class.

Uni.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24854573
You can call pointers to member functions polymorphically. So, if you want to define the listener in derived classes but use it in the context of the super class just make it virtual. When you can pass around the this pointer as a pointer to the super (base) class and still bind it to the method of the sub (derived) class and it will behave as a polymorphic function.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854583
>>You can call pointers to member functions polymorphically....
Erm, I think I follow that... Although as above with my reply to MrJoltCola, that way would mean derived classes couldn't use any method they wished as a listener and would be stuck to using the virtual methods defined in CEventListener.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24854587
>> I could make a static method in the class CListener1, which then passes it to the correct member function within its class, but I'm trying to find a way around that...

You've lost me too now.

What I meant when suggesting a static member function, is that you can define as many of them as you want, in any class you want, and as long as they take no parameters, and return void (ie. they fit the function pointer), they can be used with the addEventListener method.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24854597
Anyway, I'm off to bed now, so I'll leave you in the capable hands of my colleagues ;)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854599
Hehe, okay cheers Infinity. :)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854607
Okay - clearly me explaination skills are shoddy... I'll start at the beginning of how I came to where I am... Reply coming up...
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24854608
>>then I cannot have more than one eventRaised method within the derived class

Well, you could not have more than one anyway unless you are overloading it. Are you overloading?
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24854643
Bed time for me too (like I told MJC about 1/2 hrs ago!)... night Uri.... good luck MJC :)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854651
Later mate. :)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854675
A member function can be done as follows:

**********************************************************************
class CListener{
      void eventListener();
};

class CSender{
      void addListener(CListener *aEventListener, void (CListener ::*aMemberFunction)());
};

int main(){
      CListener objListener;
      CSender objSender;
      objListener.addListener(&objListener, &CListener::eventListener);
}
**********************************************************************

The issue with the above code is that CSender::addListener can only accept CListener objects and methods contained within. I could also make the eventListener method virtual (don't think this code is correct...):

**********************************************************************
class CListenerDefinition{
      virtual void eventListener()=0;
};

class CListener:public CListenerDefinition{
      void eventListener(){};
};

class CSender{
      void addListener(CListenerDefinition *aEventListener);
      //Further methods here call the overrided method eventListener.
};

int main(){
      CListener objListener;
      CSender objSender;
      objListener.addListener(&objListener);
}
**********************************************************************

The issue with this is that there can only be one eventListener method in a derived class of CListenerDefinition.

So, what I'm trying to do is 'expand' the top way of doing things by removing the dependancy of CSender only being able to accept pointers of member functions to CListener.

Hope that clears things up...
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854809
...and continuing on with the hope of making things clearer:

The issue with this is that there can only be one eventListener method in a derived class of CListenerDefinition.
If I have something like eventListener(uint) and eventListener(uint, uint), then I no longer have just one eventListener method, there are 3 with 2 being overloads. Something that could be done is to have CListenerDefinition have a number of eventListener methods such as eventListener1(), eventListener2(), eventListener3() etc. But again, this falls down to the issue of functions within CListener not being name friendly - not forgetting that when coding from int main(), I would have to know that CListener::eventListener() does job X, rather than have a method CListener::doJobX().

A further issue with this overriding 'solution' is that I can only have the number of listeners in CListener as there are eventListener methods within the base class CListenerDefinition which is not ideal.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24854995
IMPORTANT:
Just realised, in the above code snippets I say:      
      objListener.addListener(&objListener);
This should read:
      objSender.addListener(&objListener);
0
 
LVL 40

Assisted Solution

by:mrjoltcola
mrjoltcola earned 160 total points
ID: 24854999
I am not quite sure why you must use pointers to members, but could you use something like this? It is a base class thunk to a virtual function. So the function pointer is always the base class type.

Again, I am not sure you need pointers to functions anyway but perhaps its been too long of a day for both of us.

See below, it works, and is for discussion, not necessarily a solution.


#include <iostream>
 

using namespace std;
 
 

class CEventListener{

   public:

     virtual void listener()  { cout<<"CEventListener(Base)::listener()\n"; doit(); }

     virtual void doit() { cout<<"CEventListener(Base)::doit()\n"; }
 

     typedef void (CEventListener::*FuncPtr)();
 

};
 
 

class CEventSender{

  public:
 

      bool addEventListener(CEventListener *aEventListener, CEventListener::FuncPtr fun){

         ((aEventListener->*fun))();

         return true;

      }

};
 

class CListener1: public CEventListener{

public:

     virtual void doit() { cout<<"CEventListener(Derived)::doit()\n"; }
 

     void eventReceived(){

     }

};
 

int main(){

        CEventSender objEventSender1;

        CListener1 objListener1;

        objEventSender1.addEventListener(&objListener1, &CListener1::listener);

        return 0;

}

Open in new window

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855009
...continuation once more...

So, what I'm trying to do is 'expand' the top way of doing things by removing the dependancy of CSender only being able to accept pointers of member functions to CListener.
See, the only way I know of removing CSenders dependancy on CListener is by using templates, but the issue with this is that CSender could no longer accept multiple CListener-type objects in the same object. For example in the code below the last line falls flat on its face as CSender can only contain CListener1 type objects.

**********************************************************************
class CListener1{
      void eventListener1();
};

class CListener2{
      void eventListener2();
};

template<typename TListenerClassName>
class CSender{
      void addListener(TListenerClassName *aEventListener, void (TListenerClassName::*aMemberFunction)());
};

int main(){
      CListener1 objListener1;
      CListener2 objListener2;
      CSender<CListener1> objSender;
      objSender.addListener(&objListener1, &CListener1::eventListener);
      objSender.addListener(&objListener2, &CListener2 ::eventListener);
}
**********************************************************************

Hope everybody has followed so far... I think this is where I will lose you... So, rather than using templates I am wanting to be able to say of each class:

**********************************************************************
CListener - this is a general class doing nothing more than providing a common base class for any class that wishes to listen for events.

CSender - this is a class which accepts class objects that are derived from CListener. When it accepts class objects, it also accepts a pointer to a member function that will exist in a class derived from CListener.
**********************************************************************

The main issue is that CListener contains no methods itself, but the derived classes do, and it is those that I'm wanting a pointer to so that I am able to call them. I think as it stands CListener could be removed, and the eventListener methods could be static to give:

**********************************************************************
class CListener1{
      static void eventListener1();
};

class CListener2{
      static void eventListener2();
};

class CSender{
      void addListener(void (*aMemberFunction)());
};

int main(){
      CListener1 objListener1;
      CListener2 objListener2;
      CSender objSender;
      objSender.addListener(&CListener1::eventListener);
      objSender.addListener(&CListener2::eventListener);
}
**********************************************************************

Which works (which is what Infinity suggested), although this then means that I can't call any member functions on either CListener1 or CListener2. To change this I could have something as follows:

**********************************************************************
class CListener1{
      static void eventListener1(void *aMember);   //Calls memberEventListener1 after typecasting the arg.
      void memberEventListener1();
};

class CListener2{
      static void eventListener2(void *aMember);   //Calls memberEventListener2 after typecasting the arg.
      void memberEventListener2();
};

class CSender{
      void addListener(void (*aMemberFunction)(void *), void *aMember);
};

int main(){
      CListener1 objListener1;
      CListener2 objListener2;
      CSender objSender;
      objSender.addListener(&CListener1::eventListener, objListener1);
      objSender.addListener(&CListener2::eventListener, objListener2);
}
**********************************************************************

Thing is, this is slightly messy in that each memberEventListener method I have to have an equivalent static method (or one if I use some method identification within the static method to state which method I wish to call).

So, my overall goal is to move this static method functionality within the CSender class...

Hope that hels! :)
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24855040
<quote>
class CListener1{
     void eventListener1();
};

class CListener2{
     void eventListener2();
};
</quote>

It appears what you are trying to do is akin to an interface or mixin, without inheritance, but that is not C++, in C++ we do this by inheritance. Interfaces are defined by a base class and implemented by the derived classes, its that simple. C++ does not provide, at the language level, a feature that says "if it quacks like a duck it must be a duck", it provides "if it has duck genes then it is a duck". This is type safety.
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24855048
>>So, what I'm trying to do is 'expand' the top way of doing things by removing the dependancy of CSender only being able to accept pointers of member functions to CListener

Why is this dependency a bad thing? If you want that, why use classes at all? You can just use plain old C style functions, which have no class type associated.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855074
>>Why is this dependency a bad thing?
Because I may have two listeners that want to listen for the same event, but they both cannot be added to CSender as CSender can only accept the type CListener1 or CListener2.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855078
>>It appears what you are trying to do is akin to an interface or mixin, without inheritance, but that is not C++, in C++ we do this by inheritance.
Just to possibly state the obvious, I'm not necessarily wanting to use inheritance and virtual functions, they are merely a way that I thought I could achieve what I'm after. I'm open to any suggestions...
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24855118
>>>>Why is this dependency a bad thing?
>>Because I may have two listeners that want to listen for the same event, but they both cannot be added to CSender as CSender can only accept the type CListener1 or CListener2.

That doesn't sound right to me. I think it would be clearer with a concrete implementation of CSender. As of now, you don't have one. Consider how you would write CSender. Is there to be a list<> of listeners that you will iterate?

Lets implement CSender::addListener()
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855123
>>Is there to be a list<> of listeners that you will iterate?
Yes.
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24855177
Then that list can contain any derived class of CListener. Again, show me an implementation of CListener as is in your mind. I am thinking pointers to functions may not be needed. Perhaps plain virtual functions are adequate.

foreach listener in list
   listener->fun()

If the fun() is a virtual function of CListener, all classes deriving will implement it. The only reason to use pointers to members would be if a specific listener class needs multiple functions. In that case you can take my suggestion above regarding "thunks" and add a base class function for each, which will call the corresponding derived virtual method, implemented in the derived class. If the base class provides a default implementation for each, then the derived classes would only need to implement/override the ones they wanted to change.

0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855214
>>Perhaps plain virtual functions are adequate.
I don't think they will do what I'm after because I may not want CListener1 to have the method fun(), I may want the method to be called something more relevant to what CListener1 should do. Take this example for instance:


CEmergencyDispatcher:public CEventListener{
      void sendEmergencyResponse(unsigned int aLocation);
};

CNewsCrew:public CEventListener{
      void sendNewsTeam(unsigned int aLocation);
};

CVehicle:public CSender{
      void crashed();
};


CVehicle has been set up so that the crashed method from CVehicle calls the sendEvent method that is part of CSender. This has been set up so that this event sender calls the methods in CEmergencyDispatcher and CNewsCrew with the location. Now I may have a different CSender class such as:

CInterview:CSender{
      void setupInterview();
};

where the setupInterview would call only the method of the CNewsCrew class.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855225
Also, just to expand on why I don't think virtual functions would help. Consider if CEmergencyDispatcher looked like:

CEmergencyDispatcher:public CEventListener{
      void sendEmergencyResponse(unsigned int aLocation);
      void sendInvestigationUnit(unsigned int aLocation);
};

there are two seperate event listeners for this class.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24855254
MJC, I hope you don't mind but I'm afraid I'm going to have to go to bed - starting to fall asleep here... I shall be back around 9:30 GMT... :)

Thanks for your help,
Uni
0
 
LVL 40

Expert Comment

by:mrjoltcola
ID: 24855345
No problem. Perhaps evilrix can help you in the morning, GMT. I am EST. I can see what you are attempting, but I have issues with the approach from a design perspective. You can simply write individual classes per event, if you want, and register those. I think perhaps you are caught up on the actual naming signature of a method. Thats another reason I say use a base class dispatch thunk method (which is always named func()) and implement the thunk in each derived class. For a dispatcher, you could write multiple queues/lists so each event has its own list of listeners and you call fun() on each. I still see no problem with a single listen() function per listener. The only issue that arises is if you want one listener to simultaneously listen for multiple, different events. In this scenario, I don't see a need for that.

Keep in mind, forcing the issue with C++ pointers to members may not win you as much performance as you think, over if/then/else or switch. They are not like C pointers to functions, which are super fast. C++ actually uses some overhead due to the additional typing and virtual dispatching features.

0
 
LVL 40

Accepted Solution

by:
evilrix earned 170 total points
ID: 24856937
I'm back.

I'm not quite sure why you can't just use polymorphic member function pointers (like I suggested above -- although I was tired so maybe I did a poor job of explaining myself). Your sender class can accept pointers to members of type T * where T is the base class of all your listeners. This is an interface that should declare a pure and virtual (abstract) eventListener, which your subclasses override. You can then pass in the member function pointers to the subclasses but when you call them you still only need to bind them to T * but because they are virtual they will still be called in the correct context.

Note all event hander functions must have the same signature and you cannot have listener specific events, because everything must happen in the context of the base class; you can only define event handers that are declared as virtual in the base class. This cannot be avoided because C++ is strongly typed (as MJC was saying above). What you can do though is have one listener for each even you need to handle. If the events need to share state there is no reason why they can't both have a pointer to shared implementation (although this should be reference counted... say using a boost shared_ptr).

BTW: List is not the best container to use for this... use a vector it is far more efficient in terms of storage and access times.

#include <iostream>

#include <vector>
 

// Base class of all listener

class CListenerBase

{

public:

   // This MUST be virtual

   virtual void eventListener() = 0;

};
 

// Make code more readable

typedef void (CListenerBase::*listener_fp_t)();
 

// An example listener

class CListener1 : public CListenerBase

{

public:

   void eventListener()

   {

      std::cout << "CListener1::eventListener()" << std::endl;

   }
 

   // If I need to share state with CListener2 I can have a smart

   // pointer to a struct that is our shared state here

};
 

// An example listener

class CListener2 : public CListenerBase

{

public:

   void eventListener()

   {

      std::cout << "CListener2::eventListener()" << std::endl;

   }
 

   // If I need to share state with CListener1 I can have a smart

   // pointer to a struct that is our shared state here

};
 

// A class that uses polymorphic listeners

template<typename TListenerBase>

class CSender

{

private:

   typedef std::pair<TListenerBase *, listener_fp_t> objptr_funcptr_pair_t;
 

public:

   void addListener(TListenerBase *aEventListener, listener_fp_t listener_fp)

   {

      m_listener_fps.push_back(std::make_pair(aEventListener, listener_fp));

   }
 

   void invokeListeners()

   {

      for(std::vector<objptr_funcptr_pair_t>::const_iterator itr = m_listener_fps.begin() ;

         itr != m_listener_fps.end() ; ++itr)

      {

         // Invoke member functions polymorphically

         ((itr->first)->*itr->second)();

      }

   }
 

private:

   // A vectort used to hold the objptr and the funcptr to bind with it

   std::vector<objptr_funcptr_pair_t> m_listener_fps;

   TListenerBase * m_aEventListener;

};
 

int main(){

   CListener1 objListener1;

   CListener2 objListener2;
 

   CSender<CListenerBase> objSender;
 

   objSender.addListener(&objListener1, &CListenerBase::eventListener);

   objSender.addListener(&objListener2, &CListenerBase::eventListener);
 

   objSender.invokeListeners();

}

Open in new window

0
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 170 total points
ID: 24857747
I've had some fun this morning too heh. I tried to get all your requirements in (as far as I understood them), and came up with the following.

Advantages :
(a) the main code is "clean"
(b) you can have as many listeners as you want with any names you want, as long as they match the prototype (ie. they take a reference to a ListenerBase as parameter, and return void), so it's quite flexible.

Disadvantages :
(a) the static_casts aren't really pretty (but they shouldn't cause a problem either if used correctly)
#include <iostream>

#include <utility>

#include <vector>
 

class ListenerBase {

};

typedef void (*Listener)(ListenerBase &obj);
 

class Listener1 : public ListenerBase {

  private :

    int value;
 

  public :

    Listener1(int v) : value(v) { }
 

    static void eventListener1(ListenerBase &obj) {

      Listener1 &objC = static_cast<Listener1&>(obj);

      std::cout << "Listener1::eventListener1 -> value = " << objC.value << std::endl;

    }
 

    static void eventListener2(ListenerBase &obj) {

      Listener1 &objC = static_cast<Listener1&>(obj);

      std::cout << "Listener1::eventListener2 -> value = " << objC.value << std::endl;

    }

};
 

class Listener2 : public ListenerBase {

  private :

    double value;
 

  public :

    Listener2(double v) : value(v) { }
 

    static void eventListener1(ListenerBase &obj) {

      Listener2 &objC = static_cast<Listener2&>(obj);

      std::cout << "Listener2::eventListener1 -> value = " << objC.value << std::endl;

    }
 

    static void eventListener2(ListenerBase &obj) {

      Listener2 &objC = static_cast<Listener2&>(obj);

      std::cout << "Listener2::eventListener2 -> value = " << objC.value << std::endl;

    }

};
 

class Sender {

  private :

    std::vector<std::pair<ListenerBase*, Listener> > listeners;

  

  public :

    void addListener(ListenerBase &obj, Listener listener) {

      listeners.push_back(std::pair<ListenerBase*, Listener>(&obj, listener));

    }
 

    void triggerListeners() {

      std::vector<std::pair<ListenerBase*, Listener> >::iterator it;

      for (it = listeners.begin(); it != listeners.end(); ++it) {

        it->second(*(it->first));

      }

    }

};
 

int main(void) {

  Listener1 objListener1a(5);

  Listener1 objListener1b(10);

  Listener2 objListener2(15.5);

  Sender objSender;

  objSender.addListener(objListener1a, Listener1::eventListener1);

  objSender.addListener(objListener1b, Listener1::eventListener2);

  objSender.addListener(objListener2, Listener2::eventListener2);

  objSender.triggerListeners();

  return 0;

}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24857798
Then I set forth to try to get the static_casts out of the listener implementations and into a more central location, and came up with the following.

Advantages :
(a) the main code is "clean"
(b) the listener classes (Listener1 and Listener2 in the example) are clean too. They use member functions for the listener implementations, and have one dispatcher that maps the enum value to the proper event handler (kind of like a poor man's virtual functions lol). All the more difficult code is hidden in the other classes.

Disadvantages :
(a) the enum definition is common for all listeners, which makes it harder to implement listeners separately (ie. in isolation of the rest of the code). This can be solved however by casting enum values to ints when passing them through the addListener function, and back to the appropriate enum values in the triggerListener function.
(b) it's not very pretty, and looks a bit over-engineered lol ... it's a lot of effort just to keep the listener classes clean.
#include <iostream>

#include <utility>

#include <vector>
 

typedef enum {

  LT_eventListener1,

  LT_eventListener2

} ListenerType;
 
 

class ListenerBase;

typedef void (*Listener)(ListenerType, ListenerBase&);
 

class ListenerBase {

  public :

};
 

template <typename ListenerDerived>

class ListenerInter : public ListenerBase {

  public :

    static void triggerListener(ListenerType type, ListenerBase &listener) {

      ListenerDerived::eventDispatcher(type, static_cast<ListenerDerived&>(listener));

    }

};
 

class Listener1 : public ListenerInter<Listener1> {

  private :

    int value;
 

  public :

    Listener1(int v) : value(v) { }
 

    static void eventDispatcher(ListenerType type, Listener1 &obj) {

      switch (type) {

        case LT_eventListener1 : obj.eventListener1(); break;

        case LT_eventListener2 : obj.eventListener2(); break;

      }

    }
 

    void eventListener1() {

      std::cout << "Listener1::eventListener1 -> value = " << this->value << std::endl;

    }
 

    void eventListener2() {

      std::cout << "Listener1::eventListener2 -> value = " << this->value << std::endl;

    }

};
 

class Listener2 : public ListenerInter<Listener2> {

  private :

    double value;
 

  public :

    Listener2(double v) : value(v) { }
 

    static void eventDispatcher(ListenerType type, Listener2 &obj) {

      switch (type) {

        case LT_eventListener1 : obj.eventListener1(); break;

        case LT_eventListener2 : obj.eventListener2(); break;

      }

    }
 

    void eventListener1() {

      std::cout << "Listener2::eventListener1 -> value = " << this->value << std::endl;

    }
 

    void eventListener2() {

      std::cout << "Listener2::eventListener2 -> value = " << this->value << std::endl;

    }

};
 

class Sender {

  private :

    typedef struct ListenerData {

      ListenerBase *obj;

      Listener trigger;

      ListenerType type;

      ListenerData(ListenerBase *o, Listener tr, ListenerType t) : obj(o), trigger(tr), type(t) { }

    } ListenerData;

    std::vector<ListenerData> listeners;

  

  public :

    template <typename ListenerDerived>

    void addListener(ListenerDerived &obj, ListenerType type) {

      listeners.push_back(ListenerData(&obj, ListenerDerived::triggerListener, type));

    }
 

    void triggerListeners() {

      std::vector<ListenerData>::iterator it;

      for (it = listeners.begin(); it != listeners.end(); ++it) {

        ListenerData &data = *it;

        data.trigger(data.type, *(data.obj));

      }

    }

};
 

int main(void) {

  Listener1 objListener1a(5);

  Listener1 objListener1b(10);

  Listener2 objListener2(15.5);

  Sender objSender;

  objSender.addListener(objListener1a, LT_eventListener1);

  objSender.addListener(objListener1b, LT_eventListener2);

  objSender.addListener(objListener2, LT_eventListener2);

  objSender.triggerListeners();

  return 0;

}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24857804
I wouldn't really recommend either of these methods I posted. They were just a bit of fun getting them to work, and maybe might give you some ideas ...
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24858182
Hi both,

Thanks for your input - sorry I'm running late... neighbourhood appeared to have lost power for the morning... I shall split the points between the three of you providing nobody objects to such?

Thank you,
Uni
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24858907
Not at all. Does anything that was posted do what you wanted in a way that you can live with ? Or do you need some further brainstorming ?
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24858937
>>Not at all. Does anything that was posted do what you wanted in a way that you can live with ?
No, I think what has been posted by everybody has been sufficient... :) I'm guessing evilrix is having a busy day at the office, still just out of courtesy I'd like to make sure he doesn't object to sharing the points... :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24858978
>> I'm guessing evilrix is having a busy day at the office
Yeah ---> http:/Q_24571684.html ---{ even experts need a little help sometimes }

>> I'd like to make sure he doesn't object to sharing the points
Nope, as long as you are happy and the answers you select have PAQ value I am a happy bunny :)

Thanks Uri.
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24859085
>>even experts need a little help sometimes
*Gasp* *Huuuu* *Jaw drop to floor*... You're human?!? Hm, I'm familiar with quite a number of compression algorithms, but can't say I've ever heard of that one before... certainly isn't mainstream, mind me asking what type of data are you compressing?

>>Nope, as long as you are happy and the answers you select have PAQ value I am a happy bunny :)
Very well. :)
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24859163
>> You're human?
Yeah, but notice Infinity08 isn't :)

>> mind me asking what type of data are you compressing?
Proprietary :)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24859237
>>Yeah, but notice Infinity08 isn't :)
True... true... ;)

>>Proprietary :)
Hehe, fair enough. ;) Here's a site which compares a fair number of compression programs on different types of data. The best ones are open-source, so if you find that the 3R doesn't do what you're after then you may find something on that site...

Cheers all,
Uni
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24859243
0
 
LVL 3

Author Closing Comment

by:Unimatrix_001
ID: 31603504
Thank you! :)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24859820
>> >> You're human?
>> Yeah, but notice Infinity08 isn't :)

But ... "I want to be a real boy !"
0
 
LVL 40

Expert Comment

by:evilrix
ID: 24859875
>> so if you find that the 3R doesn't do what you're after
Unfortunately, it's already in use and I need to understand it :(

Nice link though (bookmarked)... have 500 pts on me :)

>> I want to be a real boy
Oh dear!
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24860056
>> >> I want to be a real boy
>> Oh dear!

Let's see if this one rings a bell : "I'm sorry I'm not real. If you let me, I'll be so real for you! "
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24860167
>>But ... "I want to be a real boy !"
Hahahahaha! :D That's brilliant...

>>Unfortunately, it's already in use and I need to understand it :(
Ah... not to worry... Infinity is on it, you'll understand it soon after he has completed the telepathic mind-meld... ;)

>>Nice link though (bookmarked)... have 500 pts on me :)
Wow! Thank you very much! :)

>>Let's see if this one rings a bell : "I'm sorry I'm not real. If you let me, I'll be so real for you! "
Can't say that one is familiar to me... sounds like something that could be from an virtual adult site... Anything you want to share with the community Infinity? ;)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24860205
>> sounds like something that could be from an virtual adult site... Anything you want to share with the community Infinity? ;)

Not really, unless you're also into egg whiskers, feather dusters and flying helmets (one more reference ... I'm on a roll here lol).

The quote is from the modern day Pinocchio movie : A.I. ;)
0
 
LVL 3

Author Comment

by:Unimatrix_001
ID: 24860273
>>The quote is from the modern day Pinocchio movie : A.I. ;)
Oh!... That film was creepy! Worse than the Final Fantasy film with the uncanny valley...
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now