Xcpp interfaces provide the means to "wire up" software components more efficiently than with conventional C++ or with languages like C# and Java. The normal approach is to heap allocate the wiring. For example, Java programs often use anonymous inner classes while C# programs often use delegates for this purpose.
This example shows how a CD Player can internally wire its play and stop buttons to its Play() and Stop() methods without heap allocations.
Consider that the public header file Button.h defines an interface IButtonListener. A client is expected to implement this interface in order to receive a notification that a button has been pressed.
/////////////////// Button.h ///////////////////
$interface IButtonListener
{
void OnButtonPressed();
};
class Button
{
public:
void SetEventHandler(ptr<IButtonListener> h)
{
eventHandler = h;
}
void OnMouseClicked()
{
eventHandler->OnButtonPressed();
}
private:
ptr<IButtonListener> eventHandler;
};
A client calls SetEventHandler() in order to set the event handler that receives the notification message that the button has been pressed.
It is assumed the GUI framework calls OnMouseClicked() when the user clicks the mouse button while the mouse cursor is over the button. The implementation of OnMouseClicked() sends a notification to the client that the button has been pressed.
Now consider the implementation of CDPlayer, as follows:
/////////////////// CDPlayer.cpp ///////////////////
@import "Button.h"
class CDPlayer
{
public:
CDPlayer()
{
struct B1 : public CDPlayer
{
void OnButtonPressed() {Play(5);}
};
playButton.SetEventHandler((B1*)this);
struct B2 : public CDPlayer
{
void OnButtonPressed() {Stop();}
};
stopButton.SetEventHandler((B2*)this);
}
void Play(int speed);
void Stop();
private:
Button playButton;
Button stopButton;
};
Note how the CDPlayer has two Button member variables. These need to be "wired up" so they call the Play() and Stop() methods respectively.
The interesting idea is that we can write a struct named B1 that subclasses CDPlayer. This adds member functions but no member variables (i.e. no state) to the CDPlayer class. Therefore it is reasonable to reinterpret a CDPlayer as a B1 which can in turn be coerced into an IButtonListener because it implements OnButtonPressed() as required.
The upshot is that the CDPlayer can implement the IButtonListener interface for the purposes of receiving the OnButtonPressed() notification from its play button. Similarly, the CDPlayer can implement the IButtonListener interface again (and differently) for its stop button.
This technique is unconventional but very powerful and efficient. Unlike Java anonymous inner classes or C# delegates (for example) no heap allocation is required at all to allow a button to send a message to its CDPlayer.