Sure. I wrote this for a scenario that includes a button. When the button is pressed, it raises an event.
The abstract class is called IButtonEvents. It is the interface between the Button class and, in this instance, the SomeEventHandler class. Here is the header for IButtonEvents:
Code:
#pragma once
class IButtonEvents
{
public:
virtual ~IButtonEvents(); // Virtual Destructor.
// Purpose: Function declaration for function thats represents an event. Must be overridden in
// a derived class.
//---------------------------------------------------------------------------------------------------
virtual void _OnPress() = 0; // Is raised when a button is pressed.
};
Since I used a virtual destructor, I must provide implementation for it. Here is IButtonEvents.cpp:
Code:
#include "IButtonEvents.h"
IButtonEvents::~IButtonEvents()
{
}
I just created a class called SomeEventHandler that inherits the interface, overrides the _OnPress function and provides implementation. Here is the header for SomeEventHandler:
Code:
#pragma once
#include <iostream>
#include "IButtonEvents.h"
using namespace std;
class SomeEventHandler : public IButtonEvents
{
private:
void _OnPress(); // The overidden function of the inherited virtual function.
// AKA, the EventHandler.
};
The implementation for _OnPress just cout's the memory address of the object and identifies the function. Here is the source for SomeEventHandler:
Code:
#include "SomeEventHandler.h"
void SomeEventHandler::_OnPress()
{
// Display a response message identifying the object and the event.
cout << "Object at " << this << " responding to _OnPress event." << endl;
}
For the Button class, I used a linked list of pointers, like I was talking about in the previous post. You can ignore that code. The only thing worth noting is the function AddEventHandler. Notice that an implicit conversion takes place in the parameters. Here is the header for the Button class:
Code:
#pragma once
#include "IButtonEvents.h"
class Button
{
private:
struct EventHandlerRecord // The record structure for the table of EventHandlers
{
IButtonEvents * Object; // Pointer to an EventHandling object
EventHandlerRecord * NextRecord; // Pointer to the next record
};
EventHandlerRecord * FirstRecord; // The pointer to the first record
EventHandlerRecord * LastRecord; // The pointer to the last record
public:
Button::Button(); // Default Constructor
Button::~Button(); // Default Destructor
// Parameters: A pointer to an object derived from the IButtonEvent class.
// Purpose: Adds a record the EventHandler table.
//-----------------------------------------------------------------------------------
void AddEventHandler(IButtonEvents * EventHandlerObject);
// Purpose: Raises the _OnPress event function
//-----------------------------------------------------------------------------------
void Press();
};
There isn't much worth noting in the source for this class, just that it calls the _OnPress function from the IButtonEvents class. Here is the source for the Button class:
Code:
#include "Button.h"
Button::Button()
{
/* ===Initialize pointers=== */
Button::FirstRecord = 0;
Button::LastRecord = 0;
}
Button::~Button()
{
/* ===Destroy the EventHandler table=== */
// create a cursor
Button::EventHandlerRecord * cursor;
// while a record exists . . .
while (Button::FirstRecord != 0)
{
// . . . point the cursor to the first record
cursor = Button::FirstRecord;
// move the FirstRecord to the next record
Button::FirstRecord = Button::FirstRecord->NextRecord;
// delete the record at the cursor
delete cursor;
}
}
void Button::AddEventHandler(IButtonEvents * EventHandlerObject)
{
// Create a cursor
Button::EventHandlerRecord * cursor;
// Create a new record
cursor = new Button::EventHandlerRecord;
// Set the Object field
cursor->Object = EventHandlerObject;
// If the first record hasn't been assigned yet . . .
if (FirstRecord == 0)
{
// . . . make the new record the first record
Button::FirstRecord = cursor;
}
// Else . . .
else
{
// . . . append the record to the last record
Button::LastRecord->NextRecord = cursor;
}
// Make the new record the last record
cursor->NextRecord = 0;
Button::LastRecord = cursor;
}
void Button::Press()
{
/* ===Call the _OnPress function for each object in the EventHandler table=== */
// Create a cursor
Button::EventHandlerRecord * cursor;
// Start at the first record
cursor = Button::FirstRecord;
// While the cursor points to a record . . .
while (cursor != 0)
{
// . . . Call the _OnPress function for that object
cursor->Object->_OnPress();
// Move to the next record
cursor = cursor->NextRecord;
}
}
Finally, here is main.cpp:
Code:
#include <iostream>
#include "Button.h"
#include "SomeEventHandler.h"
using namespace std;
int main()
{
Button myButton; // Button object
SomeEventHandler * EventHandler1 = new SomeEventHandler; // An event handler object
SomeEventHandler * EventHandler2 = new SomeEventHandler; // Another event handler object
// Add the EventHandlerObjects to myButton's EventHandler table
myButton.AddEventHandler(EventHandler1);
myButton.AddEventHandler(EventHandler2);
// Press the button
myButton.Press();
// Wait for the new line character
cin.get();
// Destroy the EventHandler objects
delete EventHandler2;
delete EventHandler1;
return 0;
}
That's it. I believe it is a fail-safe design, excluding multiple inheritance. To support aysnchronous calls wouldn't take much work. The only drawback is that an EventHandling class has to inherit the interface, which means they must be designed to handle the events, and can't be bound during run-time. Another layer of abstraction could solve that.