Jump to content

C++ events


Laurens
 Share

Recommended Posts

Hello,

 

Coming from C# I have a difficult time comprehending events in C++. All I found on Google was twenty different snippets of code with little explanation, which is why I am asking here. My situation is as follows:

 

I have a State class which is the base class for GameState and PauseState. The state is responsible for handling input from the player. Managing the states is the StateManager. The StateManager is capable of switching between states.

Currently, the constructor of State requires a reference to the StateManager so it can call the SetState method in it. I find this a horrid solution and wish to implement it so that StateManager subscribes to a StateChanged event in the State class which can then be fired when the escape key is pressed ala C#.

 

How would I go about implementing such a system in C++?

 

Thanks!

Link to comment
Share on other sites

Take a look at my blog as I detailed a subscribe and notify system in there for my Player and User Input class. The Player class registers events with the User Input class and gets notified when they occur.

 

It's the 'For those who might be interested' post in September

  • Upvote 1

Intel Core i5 2.66 GHz, Asus P7P55D, 8Gb DDR3 RAM, GTX460 1Gb DDR5, Windows 7 (x64), LE Editor, GMax, 3DWS, UU3D Pro, Texture Maker Pro, Shader Map Pro. Development language: C/C++

Link to comment
Share on other sites

I also have an event system that I've used a few years. The perk that this system has over most, not to take anything away from Pixel's system, is that it doesn't require your class methods to be static. You can run into scope issues with class data and static methods. I'll try to find it. The implementation is kind of complex, but the usage is very simple. Here would be an example of the usage:

 

class Button
{
private:
public:
Event1<int> OnClick;
};

class MyForm
{
private:
void cmdExit_Click(int i) {}
public:
Button* cmdExit;
MyForm()
{
	cmdExit = new Button();
	cmdExit->OnClick.Bind(this, MyForm::cmdExit_Click);
}
};


MyForm frm;

// this will end up calling MyForm::cmdExit_Click()
// the cool thing is that I have it setup so you can have a calling chain. I can any number
// of different methods to the cmdExit->OnClick, and when I .Raise() the event all the
// functions tied to it will be called
frm.cmdExit->OnClick.Raise(5)

 

One of the cool things also is that your function that handles your event can also be private to the class to prevent anyone from calling the event function directly.

Link to comment
Share on other sites

You're welcome Laurens.

 

Sounds interesting Rick. I'd be interested in seeing the implementation of that if you can find it. I'm always up for integrating better solutions if I can find them.

Intel Core i5 2.66 GHz, Asus P7P55D, 8Gb DDR3 RAM, GTX460 1Gb DDR5, Windows 7 (x64), LE Editor, GMax, 3DWS, UU3D Pro, Texture Maker Pro, Shader Map Pro. Development language: C/C++

Link to comment
Share on other sites

That seems really interesting Rick, the usage almost feels like C# :)

 

I would love to see the implementation if you can dig it up.

 

Cheers!

 

 

Here it is in all it's glory. It's very much like how C# handles events. If you are familiar with C# you know that all events take 2 parameters.

 

If you aren't familiar with templates your head might explode following the code below. You will note that below is for an event that takes 2 parameters to the functions that you link to it and returns a void. Because this uses templates those parameter types are defined by you like so Event2<int, string> myEvent;

 

You can just put this in a header file, and include that header file wherever you want to use this and you're good to go.

#include <list>

using namespace std;

template<class P, class Q>
class TFunctor2
{
public:
  virtual void Call(P var1, Q var2)=0;
};

template <class TClass, class param1, class param2>
class TSpecificFunctor2 : public TFunctor2<param1, param2>
{
private:
  void (TClass::*fpt)(param1, param2);
  TClass* pt2Object;         
public:
  TSpecificFunctor2(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2))
  { pt2Object = _pt2Object;  fpt=_fpt; }

  virtual void Call(param1 var1, param2 var2)
  { (*pt2Object.*fpt)(var1, var2); }
};

template<class T1, class T2>
class Event2
{
public:
  list<TFunctor2<T1, T2>* >  mCaller;

  template<class Target>
  Event2(Target* t, void (Target::*fnPtr)(T1, T2))
  { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }

  Event2(){}

  template<class Target>
  void Bind(Target* t, void (Target::*fnPtr)(T1, T2))
  { mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }

  void Raise(T1 V1, T2 V2)
  {
     list<TFunctor2<T1, T2>*>::reverse_iterator iter;


     for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
     {
        (*iter)->Call(V1, V2);
     }
  }   

  void Clear()
  {
     mCaller.clear();
  }
};

 

 

I didn't create this code so I can't take credit for it. I learned it from another game programming library, but honestly I have never seen a better C++ event system than what this gives you. This is as close to how .NET handles events that you can get in C++. It's easy to use. I would highly recommend studying the code and actually understand how it's working because it's pretty powerful, but for the first few months I just used it and didn't care how it worked :) If you want to create event functions that have different signatures then you would copy the above code, and do some renaming and re-templating. For example if you wanted a function that took 3 variables you would change the function names to have a 3 at the end, and then add another template class type to the classes. I gave you 2 parameter signature because that's how .NET handles events. It passes in the calling object and the parameter structure.

Link to comment
Share on other sites

Here is a small example of how to use it. This assumes you took the above code and put it in a file named Event.h

 

Widget.h

#pragma once
#include "Event.h"
#include <string>

using namespace std;

class Widget
{
private:
void Widget_onClick(Widget* w, string p);
public:
Widget(void);
~Widget(void);
public:
Event2<Widget*, string> onClick;
};

 

Widget.cpp

#include "Widget.h"

Widget::Widget(void)
{
onClick.Bind(this, &Widget::Widget_onClick);
}

Widget::~Widget(void)
{
}

void Widget::Widget_onClick(Widget *w, std::string p)
{
}

 

mian.cpp

#include "Widget.h"


int main()
{
Widget w;

w.onClick.Raise(&w, "hello");   // this will end up calling Widget::Widget_onClick which is a private function of Widget

return 0;
}

  • Upvote 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...