Saturday, March 14, 2009

C++ pointer-to-member-function events

I made an Event class that can be hooked with a member function from any class. I ended up using a combination of virtual functions, templates, and nested classes, and I was just pleased enough with the result to blag about it for a while.

Static example

class Foo {
private:
  Event _wasFrobbed;
  
public:
  Foo() { }
  Event::PublicEvent& wasFrobbed() { return _wasFrobbed.pub(); }
  void Frob() { _wasFrobbed.Fire(); }
};

void CharlesWasFrobbed() {
  cout << "Charles was frobbed\n";
}

void Test1() {
  Foo charles;
  
  //Hooking his event
  charles.wasFrobbed().Hook(&CharlesWasFrobbed);
  
  //Frobbing him
  charles.Frob();
  
  //Unhooking his event
  charles.wasFrobbed().Unhook(&CharlesWasFrobbed);
}

That's easy enough to use, but not so impressive on its own. The fun part is that it works with pointers to member functions as well!

Pointer-to-member-function example

class Bar {
private:
  Foo* _pfoo;
  
public:
  void NoticeFrob() {
    cout << "a Bar was witness to a frobbing\n";
  }
  
  Bar(Foo* pfoo) : _pfoo(pfoo) {
    //Hook the target Foo's event
    _pfoo->wasFrobbed().Hook(this, &Bar::NoticeFrob);
  }
  
  ~Bar() {
    //Unhook the target Foo's event
    _pfoo->wasFrobbed().Unhook(this, &Bar::NoticeFrob);
  }
};

void Test2() {
  Foo winston;
  Bar nigel(&winston);
  
  //Frobbing Winston ... Nigel will notice
  winston.Frob();
}

Next step: add a template parameter to the Event class itself so the event can fire with an argument.