I am getting more and more into the Pimpl idiom (private opaque pointer to real class implementation). But I still have an issue which bothers me.
How does this idiom\design pattern deal with signals in the public class (like boost or qt signals)?
class my_class : public QObject
{
Q_OBJECT
public:
void monitorstuff();
signal:
void needupdate();
private:
class impl; unique_ptr<impl> pimpl; // opaque type here
};
class my_class::impl {
void reallymonitorstuff();
};
my_class::impl::reallymonitorstuff()
{
...
//update required here
...
}
void my_class::monitorstuff()
{
pimpl->reallymonitorstuff();
}
Do I replicate all signals in the pimpl, connect with signals of the outer class? A bit annoying to have twice as much signals as what is publicly available, also annoying when I need to swap instances.
Do I pass the public instance as parameter to the private instance which calls directly the public signals
Another design mechanism in conjuction I didn't heard of?
In general, I don't really see the problem. The public class should forward all calls to the impl including calls to connect a slot. The impl contains the signal, not the public class. E.g here using Boost.Signals2:
#include <memory>
#include <boost/signals2.hpp>
#include <iostream>
using signal_type = boost::signals2::signal<void()>;
using slot_type = signal_type::slot_type;
class my_class {
public:
my_class();
void monitorstuff();
void connect(const slot_type& slot);
private:
struct impl; std::unique_ptr<impl> pimpl;
};
struct my_class::impl {
signal_type signal;
void reallymonitorstuff();
void connect(const slot_type& slot){ signal.connect(slot); }
};
void
my_class::impl::reallymonitorstuff() {
//...
signal();
//...
}
void my_class::monitorstuff() {
pimpl->reallymonitorstuff();
}
void my_class::connect(const slot_type& slot) {
pimpl->connect(slot);
}
my_class::my_class() : pimpl(std::make_unique<my_class::impl>()){}
int main() {
my_class mc;
auto slot = []{ std::cout << "Notified!\n"; };
mc.connect(slot);
mc.monitorstuff();
}
Live demo.
I wonder if your problem is more specific to Qt.
Do I replicate all signals in the pimpl, connect with signals of the outer class? A bit annoying to have twice as much signals as what is publicly available, also annoying when I need to swap instances.
No, you don't need to do that.
Do I pass the public instance as parameter to the private instance which calls directly the public signals
That is not necessary either.
Another design mechanism in conjuction I didn't heard of?
That is not necessary either.
Assuming my_class::monitorstuff is supposed raise a signal, I think all you need is:
void my_class::monitorstuff()
{
pimpl->reallymonitorstuff();
emit <<Details of signal>>;
}
pimpl does not need to be concerned with signals or slots.
Related
I've got an assignment to create a sort of a multi-platform C++ GUI library. It wraps different GUI frameworks on different platforms. The library itself provides an interface via which the user communicates uniformly regardless of the platform he's using.
I need to design this interface and underlying communication with the framework properly. What I've tried is:
Pimpl idiom - this solution was chosen at first because of its advantages - binary compatibility, cutting the dependency tree to increase build times...
class Base {
public:
virtual void show();
// other common methods
private:
class impl;
impl* pimpl_;
};
#ifdef Framework_A
class Base::impl : public FrameWorkABase{ /* underlying platform A code */ };
#elif Framework_B
class Base::impl : public FrameWorkBBase { /* underlying platform B code */ };
#endif
class Button : public Base {
public:
void click();
private:
class impl;
impl* pimpl_;
};
#ifdef Framework_A
class Button::impl : public FrameWorkAButton{ /* underlying platform A code */ };
#elif Framework_B
class Button::impl : public FrameWorkBButton { /* underlying platform B code */ };
#endif
However, to my understanding, this pattern wasn't designed for such a complicated hierarchy where you can easily extend both interface object and its implementation. E.g. if the user wanted to subclass button from the library UserButton : Button, he would need to know the specifics of the pimpl idiom pattern to properly initialize the implementation.
Simple implementation pointer - the user doesn't need to know the underlying design of the library - if he wants to create a custom control, he simply subclasses library control and the rest is taken care of by the library
#ifdef Framework_A
using implptr = FrameWorkABase;
#elif Framework_B
using implptr = FrameWorkBBase;
#endif
class Base {
public:
void show();
protected:
implptr* pimpl_;
};
class Button : public Base {
public:
void click() {
#ifdef Framework_A
pimpl_->clickA(); // not working, need to downcast
#elif Framework_B
// works, but it's a sign of a bad design
(static_cast<FrameWorkBButton>(pimpl_))->clickB();
#endif
}
};
Since the implementation is protected, the same implptr object will be used in Button - this is possible because both FrameWorkAButton and FrameWorkBButton inherit from FrameWorkABBase and FrameWorkABase respectively. The problem with this solution is that every time i need to call e.g. in Button class something like pimpl_->click(), I need to downcast the pimpl_, because clickA() method is not in FrameWorkABase but in FrameWorkAButton, so it would look like this (static_cast<FrameWorkAButton>(pimpl_))->click(). And excessive downcasting is a sign of bad design. Visitor pattern is unacceptable in this case since there would need to be a visit method for all the methods supported by the Button class and a whole bunch of other classes.
Can somebody please tell me, how to modify these solutions or maybe suggest some other, that would make more sense in this context? Thanks in advance.
EDIT based od #ruakh 's answer
So the pimpl solution would look like this:
class baseimpl; // forward declaration (can create this in some factory)
class Base {
public:
Base(baseimpl* bi) : pimpl_ { bi } {}
virtual void show();
// other common methods
private:
baseimpl* pimpl_;
};
#ifdef Framework_A
class baseimpl : public FrameWorkABase{ /* underlying platform A code */ };
#elif Framework_B
class baseimpl : public FrameWorkBBase { /* underlying platform B code */ };
#endif
class buttonimpl; // forward declaration (can create this in some factory)
class Button : public Base {
public:
Button(buttonimpl* bi) : Base(bi), // this won't work
pimpl_ { bi } {}
void click();
private:
buttonimpl* pimpl_;
};
#ifdef Framework_A
class Button::impl : public FrameWorkAButton{ /* underlying platform A code */ };
#elif Framework_B
class Button::impl : public FrameWorkBButton { /* underlying platform B code */ };
#endif
The problem with this is that calling Base(bi) inside the Button's ctor will not work, since buttonimpl does not inherit baseimpl, only it's subclass FrameWorkABase.
The problem with this solution is that every time i need to call e.g. in Button class something like pimpl_->click(), I need to downcast the pimpl_, because clickA() method is not in FrameWorkABase but in FrameWorkAButton, so it would look like this (static_cast<FrameWorkAButton>(pimpl_))->click().
I can think of three ways to solve that issue:
Eliminate Base::pimpl_ in favor of a pure virtual protected function Base::pimpl_(). Have subclasses implement that function to provide the implementation pointer to Base::show (and any other base-class functions that need it).
Make Base::pimpl_ private rather than protected, and give subclasses their own appropriately-typed copy of the implementation pointer. (Since subclasses are responsible for calling the base-class constructor, they can ensure that they give it the same implementation pointer as they plan to use.)
Make Base::show be a pure virtual function (and likewise any other base-class functions), and implement it in subclasses. If this results in code duplication, create a separate helper function that subclasses can use.
I think that #3 is the best approach, because it avoids coupling your class hierarchy to the class hierarchies of the underlying frameworks; but I suspect from your comments above that you'll disagree. That's fine.
E.g. if the user wanted to subclass button from the library UserButton : Button, he would need to know the specifics of the pimpl idiom pattern to properly initialize the implementation.
Regardless of your approach, if you don't want the client code to have to set up the implementation pointer (since that means interacting with the underlying framework), then you will need to provide constructors or factory methods that do so. Since you want to support inheritance by client code, that means providing constructors that handle this. So I think you wrote off the Pimpl idiom too quickly.
In regards to your edit — rather than having Base::impl and Button::impl extend FrameworkABase and FrameworkAButton, you should make the FrameworkAButton be a data member of Button::impl, and give Base::impl just a pointer to it. (Or you can give Button::impl a std::unique_ptr to the FrameworkAButton instead of holding it directly; that makes it a bit easier to pass the pointer to Base::impl in a well-defined way.)
For example:
#include <memory>
//////////////////// HEADER ////////////////////
class Base {
public:
virtual ~Base() { }
protected:
class impl;
Base(std::unique_ptr<impl> &&);
private:
std::unique_ptr<impl> const pImpl;
};
class Button : public Base {
public:
Button(int);
virtual ~Button() { }
class impl;
private:
std::unique_ptr<impl> pImpl;
Button(std::unique_ptr<impl> &&);
};
/////////////////// FRAMEWORK //////////////////
class FrameworkABase {
public:
virtual ~FrameworkABase() { }
};
class FrameworkAButton : public FrameworkABase {
public:
FrameworkAButton(int) {
// just a dummy constructor, to show how Button's constructor gets wired
// up to this one
}
};
///////////////////// IMPL /////////////////////
class Base::impl {
public:
// non-owning pointer, because a subclass impl (e.g. Button::impl) holds an
// owning pointer:
FrameworkABase * const pFrameworkImpl;
impl(FrameworkABase * const pFrameworkImpl)
: pFrameworkImpl(pFrameworkImpl) { }
};
Base::Base(std::unique_ptr<Base::impl> && pImpl)
: pImpl(std::move(pImpl)) { }
class Button::impl {
public:
std::unique_ptr<FrameworkAButton> const pFrameworkImpl;
impl(std::unique_ptr<FrameworkAButton> && pFrameworkImpl)
: pFrameworkImpl(std::move(pFrameworkImpl)) { }
};
static std::unique_ptr<FrameworkAButton> makeFrameworkAButton(int const arg) {
return std::make_unique<FrameworkAButton>(arg);
}
Button::Button(std::unique_ptr<Button::impl> && pImpl)
: Base(std::make_unique<Base::impl>(pImpl->pFrameworkImpl.get())),
pImpl(std::move(pImpl)) { }
Button::Button(int const arg)
: Button(std::make_unique<Button::impl>(makeFrameworkAButton(arg))) { }
///////////////////// MAIN /////////////////////
int main() {
Button myButton(3);
return 0;
}
Take this example:
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class _IEventHandler {}; // just for abstract template type
class IEvent {
public:
virtual void visitEventHandler(_IEventHandler *handler) = 0;
};
#define EXTENDS(type, parentType) \
public: \
using ParentClass = parentType; \
void visitEventHandler(_IEventHandler* handler) override { \
static_cast<IEventHandler<type>*>(handler)->on(*this); \
} \
template<typename Event>
class IEventHandler : public _IEventHandler {
public:
//virtual void on(Event& e) = 0;
void on(Event &e) {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
class EventA : public IEvent {
EXTENDS(EventA, IEvent)
};
class EventB : public EventA {
EXTENDS(EventB, EventA)
};
class EventC : public EventB {
EXTENDS(EventC, EventB)
};
class EventD : public EventC {
EXTENDS(EventD, EventC)
};
class EventBus {
public:
void fire(IEvent *event) {
while (typeid(*event) != typeid(IEvent)) {
for (_IEventHandler *handler : m_handlers[typeid(*event)])
event->visitEventHandler(handler);
// Need to update event so the loop progresses. Need to upper cast?
}
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
std::map<std::type_index, std::vector<_IEventHandler *>> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
I would like when I fire a IEvent it call on(EventX& e) on all intermediate derived class and stop on abstract class IEvent.
Currently I don't find solution, I looked about dyn_cast with a typeid, using decltype to access a static method from a instance (yes it's not the basic usage of these operators ;) and not permitted).
Summary:
The goal is to build an event system that supports hooking handlers and firing events. Events are hierarchical, deriving from a common ancestor class. Handlers should be called for their nominal event type and all types derived from that.
So far, the EventBus class is able to call handlers for the specific event type that was fired. The handlers are organized in a map from type_index to a vector of handlers. Getting the entry for a specific event type is not a problem, but how to get the less-derived types?
This is currently solve my issue:
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class _IEventHandler {}; // just for abstract template type
class IEvent {
public:
virtual void visit_IEventHandler(std::type_index _index, _IEventHandler *handler) {}
virtual std::type_index getParentTypeIndex(std::type_index index) {
return typeid(IEvent);
}
};
#define EXTENDS(type, parentType) \
public: \
using Class = type; \
using ParentClass = parentType; \
std::type_index getParentTypeIndex(std::type_index index) { \
if (index == typeid(type)) \
return typeid(ParentClass); \
else \
return ParentClass::getParentTypeIndex(index); \
} \
#define HIERARCHICAL_VISITOR(interfaceType, reelType, methodName) \
public: \
void visit##interfaceType(std::type_index _index, interfaceType* _instanceToVisit) override { \
if (_index == typeid(Class)) \
static_cast<reelType<Class>*>(_instanceToVisit)->methodName(*this); \
else \
ParentClass::visit##interfaceType(_index, _instanceToVisit); \
} \
template<typename Event>
class IEventHandler : public _IEventHandler {
public:
//virtual void on(Event& e) = 0;
void on(Event &e) {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
class EventA : public IEvent {
EXTENDS(EventA, IEvent)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventB : public EventA {
EXTENDS(EventB, EventA)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventC : public EventB {
EXTENDS(EventC, EventB)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventD : public EventC {
EXTENDS(EventD, EventC)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventBus {
public:
void fire(IEvent *event) {
std::type_index index = typeid(*event);
while (index != typeid(IEvent)) {
for (_IEventHandler *handler : m_handlers[index])
event->visit_IEventHandler(index, handler);
index = event->getParentTypeIndex(index);
}
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
std::map<std::type_index, std::vector<_IEventHandler *>> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
/*
handle 6EventD
handle 6EventC
handle 6EventA
handle 6EventA
Process finished with exit code 0
*/
The only way that I found is use the basic inheritance process with the typeid check at all stage. I don't know if is the best way, I looking for a better way ;)
The keywords for this answer are "simplify" and "encapsulate".
Let's start with simplifications. There are several elements of the question's code that serve no purpose other than making the code more complicated than it needs to be. (There might be a small performance benefit, but it is premature to worry about that.) In order to better see what the actual solution is, I think it is useful to include these improvements. On the other hand, these are only indirectly related to the actual solution, so I will refrain from giving a detailed rationale for each of these.
Rename _IEventHandler to BaseEventHandler to comply with naming requirements.
Make on() a virtual function in BaseEventHandler so that visitEventHandler() does not need a static_cast.
Make visitEventHandler() a non-virtual function since all implementations are now the same.
Declare ~IEvent() to be virtual so that IEvent still has a virtual function.
Remove the EXTENDS macro because (macros are evil and) the things it defines are no longer used.
Moving on to encapsulation, let's look at the problem from the point of view of EventBus. This class is responsible for triggering handlers in response to events. It has inferred which event each handler wants, and organized the handlers by those event types. This already breaks encapsulation a bit since the bus uses knowledge about the handler's innards. Now they want me to also know about inheritance among the event types??? I need more information or you can go handle it yourself!
Since encapsulation encourages less information, rather than more, let's consider the other option: handle it yourself! Er, let the handlers decide if they want to handle an event. This simplifies EventBus since it no longer needs to be concerned about event types. Its map containing vectors can become a single vector, its hook() method no longer needs to be a template, and its fire() method can drop the loop that has been so difficult to implement. The trade-off is that the event handlers now need to examine the event types. Fortunately, dynamic_cast makes the check very simple.
#include <iostream>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent & e) override {
// Only fire for events of the templated type.
if ( dynamic_cast<Event *>(&e) )
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
/* ** Event ** */
class IEvent {
public:
virtual ~IEvent() {} // To force run time type information (RTTI)
void visitEventHandler(BaseEventHandler* handler)
{
handler->on(*this);
}
};
class EventA : public IEvent {};
class EventB : public EventA {};
class EventC : public EventB {};
class EventD : public EventC {};
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
for (BaseEventHandler *handler : m_handlers)
event->visitEventHandler(handler);
}
void hook(BaseEventHandler *handler) {
m_handlers.push_back(handler);
}
protected:
std::vector<BaseEventHandler *> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
Some things to note about this approach:
Event handlers are fired in the order in which they were hooked. Previously, the order was handlers for the most derived class in the order they were hooked, followed by handlers for that class's direct parent in the order they were hooked, etc. If this is an important consideration, see my other answer.
There are still some issues with this code, but I am willing to chalk them up to being artifacts arising from the need to minimize the example.
There is no need to #include <typeindex>! This is good. I consider use of that header to be a yellow flag for design flaws. Better than a red flag (such as macros), but still an indication that maybe there's a better way to do things.
The keywords for this answer are "simplify" and "delegate".
Let's start with simplifications. There are several elements of the question's code that serve no purpose other than making the code more complicated than it needs to be. (There might be a small performance benefit, but it is premature to worry about that.) In order to better see what the actual solution is, I think it is useful to include these improvements. On the other hand, these are only indirectly related to the actual solution, so I will refrain from giving a detailed rationale for each of these.
Rename _IEventHandler to BaseEventHandler to comply with naming requirements.
Make on() a virtual function in BaseEventHandler so that visitEventHandler() does not need a static_cast.
Remove the EXTENDS macro because (macros are evil and) the things it defines either are no longer used or will be defined elsewhere.
Moving on to delegation, let's look at why EventBus has trouble traversing the inheritance tree of events. One reason is straight-forward: EventBus is not an event. Instead of trying to replicate the inheritance tree, let's use existing elements of the language. Instead of trying to deduce things about events, let's hand the problem off to someone who knows better, namely the event itself.
What I have in mind is a shift of responsibilities, basically shifting most of EventBus::fire() to the events' visitEventHandler(). Since each class knows its parent, it can invoke its parent's version of visitEventHandler(), stepping up the hierarchy until the end is reached. The trade-off is that the type of the map becomes public knowledge, rather than merely a private implementation detail of EventBus. Probably a fair trade.
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent &) override {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
using HandlerMap = std::map<std::type_index, std::vector<BaseEventHandler *>>;
/* ** Event ** */
class IEvent {
public:
// This is not an actual event type, so there are no handlers to visit.
virtual void visitEventHandlers(HandlerMap &) = 0;
};
// Need a definition for derived classes to call:
void IEvent::visitEventHandlers(HandlerMap &) {}
template<class Base>
class EventFrom : public Base {
public:
void visitEventHandlers(HandlerMap & handlers) override
{
// Visit the handlers for this specific event type.
for (BaseEventHandler *handler : handlers[typeid(EventFrom)])
handler->on(*this);
// Visit the handlers for the parent event type.
Base::visitEventHandlers(handlers);
}
};
using EventA = EventFrom<IEvent>;
using EventB = EventFrom<EventA>;
using EventC = EventFrom<EventB>;
using EventD = EventFrom<EventC>;
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
event->visitEventHandlers(m_handlers);
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
HandlerMap m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
Some things to note about this approach:
There is quite a bit of complexity used to make sure all event handlers for the most derived class are fired before any handlers for less derived classes. If this is not important, see my other answer.
There are still some issues with this code, but I am willing to chalk them up to being artifacts arising from the need to minimize the example.
There are no macros! (Macros are a red flag, indicating a likely design flaw.)
I would change the signature of hook() to void hook(BaseEventHandler *handler). While this means changes like eb.hook(&ehd) to eb.hook<EventD>(&ehd), it gives more freedom in defining your event handlers (no need for the IEventHandler template). Probably a good trade.
I'm experimenting with state machines and the one that I'm trying to implement uses function pointers to represent states
typedef void (*State)(Signal const&)
class StateMachine
{
public:
void exampleState(Signal const&);
private:
State m_currentState;
}
Basically, I want to derive a separate class for each signal and in each state function the state machine must be able to determine which kind of signal has been received and execute the corresponding code. A solution that I came up with is something like
class Signal {};
class MySignal: public Signal {};
void StateMachine::exampleState(Signal const& signal){
if (typeid(signal) == typeid(MySignal)){
//code here
}
// other cases...
}
First of all I'm not sure that using typeid this way is good practice. Also, this only works if Signal has at least one virtual function.
Another solution would be to define a sort of type flag like an enum, and pass the corresponding one in the derived signal constructor
enum signalType{
mySignalType
//other types
}
class Signal {
public:
Signal(signalType sig_type):m_type(sig_type){};
const signalType m_type;
};
class MySignal: public Signal {
public:
MySignal():Signal(mySignalType){};
};
void StateMachine::exampleState(Signal const& signal){
switch (signal.m_type){
case mySignalType:
//code here
break;
// other cases...
}
}
althoug this requires the enum to be extended each time a new signal class is written.
Is there a more elegant way of achieving this? Or maybe another technique that avoids this check at all? I remember having this problem in other scenarios as well, that's why the question in the title is more general than the example above.
What you want to achieve can be done through polymorphism.
Declare a method (or abstract method) in Signal, and implement it in MySignal:
class Signal {
public:
virtual void my_method() const = 0;
};
class MySignal: public Signal {
public:
void my_method() const override {
// do something
}
};
then call your method in exampleState, this will call the implemented method:
void StateMachine::exampleState(Signal const& signal){
signal.my_method();
}
Use dynamic_cast instead of typeid:
class Signal {
public:
virtual ~Signal() {}
};
class MySignal: public Signal {};
void StateMachine::exampleState(Signal const& signal){
if (dynamic_cast<MySignal const *>(&signal)){
//code here
}
// other cases...
}
I'm trying to make a connection between a function in one class so that I can call it in another class. The answers I've found are either too specific or maybe I'm missing something because I cannot for the life of me figure out what I'm doing wrong. Also, I'm a bit new to the boost library so please excuse any dumb questions I may ask.
The setup for my workflow is basically this...
class MyClass : public BaseClass {
void setup();
void myFunc(datatype);
OtherClass myOtherClass;
}
void setup()
{
OtherNamespace::addListener(this, myOtherClass);
}
namespace OtherNamespace {
class OtherClass {
signals::signal<void (datatype)> myConnection;
}
template<class A, class B>
void addListener(A * app, B & connection)
{
connection.myConnection.connect( 'I don't know what to do here' );
}
}
Basically, the addlistener function won't make the connection between the signal and the function. I know that where I don't know what to do I'm doing something wrong but I just can't figure out what about it is wrong. I'm making this as a helper function so that I can pass functions from one class to another then call them when they're attached. I'm trying to create a domino event from a websocket connection and I am clearly missing something very important. Any help would be truly appreciated.
I'm on xcode and boost and macbook pro.
You should connect to the signal a matching slot, which is a callable having the appropriate signature. The best solution is to leave the slot creation to the caller of your addListener function (the following is your code, in SSCCE form):
#include <boost/signals2.hpp>
typedef int datatype;
class BaseClass
{};
namespace OtherNamespace
{
class OtherClass
{
public:
boost::signals2::signal<void (datatype)> myConnection;
};
template<class A, class B>
void addListener(A app, B & connection)
{
connection.myConnection.connect(app);
}
}
class MyClass : public BaseClass
{
public:
void setup();
void myFunc(datatype)
{}
OtherNamespace::OtherClass myOtherClass;
};
void MyClass::setup()
{
// let the caller decide how to make the slot
OtherNamespace::addListener(boost::bind(&MyClass::myFunc, this, _1), myOtherClass);
}
I know 2 ways for desiging an event in C++:
1: Using callbacks:
typedef void (*callback_type)(void);
class my_class
{
public:
my_class(callback_type c)
{
m_callback = c;
}
void raise_event()
{
m_callback();
}
private:
callback_type m_callback;
};
2: Using virtual methods:
class my_class
{
public:
virtual void my_event() = 0;
void raise_event()
{
my_event();
}
};
class main_class : public my_class
{
public:
virtual void my_event()
{
// Handle EVENT.
}
};
Is there any other way or other idea for designing events?
and
What is the best pattern for designing events in ISO C++?
You should use Boost.Signals or Boost.Signals2.
To emulate those, you can use a collection of Boost.Function's/std::function's.
To emulate those, you use type erasure (so the virtual function route) for flexibility.
Note that none of that is too trivial, so you should really try to use an existing solution if possible.
The design will depend on the specifics of your requirements. For a nice example, see ACE Reactor.