Hi,

I want to develop a an application based on independent "CustomModule" that all derived from a base class "BaseModule" and that can send different kind of "CustomEvent" (derived from a "BaseModule" class) to each other. Each Module just knows that it is connected to others "BaseModule" (i.e. it does not know the specific type of "CustomModule" they are).

So the problem is the following: How can I specialize the code of CustomModule depending on the CustomEvent type that it receives and in the same time keeping a generic interface communication between Modules ? A precision: this code have to be wrapped in Python. So I would like to avoid the use of template class otherwise it will quickly be a mess.

Here are a piece of code (it was difficult to do it shorter) that works but I do not like the EventTypeID/downcasting mechanism. Any better idea ?

#include <stdio.h>

class BaseEvent 
{
    public:
        virtual int getEventTypeID() {return 0;};
};

class CustomEventType1: public BaseEvent 
{   
    public:
        virtual int getEventTypeID() {return 1;};
};

class CustomEventType2: public BaseEvent
{
    public:
        virtual int getEventTypeID() {return 2;};
};

class BaseModule
{
    public:
        void doSomething(BaseEvent* pEvent) {printf("BaseModule::doSomething function called\n");};
        virtual void receiveEvent(BaseEvent* pEvent) {doSomething(pEvent);};
};

class CustomModuleType1:public BaseModule
{
    public:
        void doSomething(CustomEventType1* pEvent) {printf("CustomModuleType1::doSomething function called\n");};
        virtual void receiveEvent(BaseEvent* pEvent) 
        {
            if (pEvent->getEventTypeID() == 1) {
                CustomEventType1* pCustomEventType1 = static_cast<CustomEventType1*>(pEvent);
                doSomething(pCustomEventType1);
            }
            else {
                printf("Wrong Event Type in CustomModuleType1::receiveEvent\n");
            }
        };
};

class CustomModuleType2:public BaseModule
{
    public:
        void doSomething(CustomEventType2* pEvent) {printf("CustomModuleType2::doSomething function called\n");};
        virtual void receiveEvent(BaseEvent* pEvent) 
        {
            if (pEvent->getEventTypeID() == 2) {
                CustomEventType2* pCustomEventType2 = static_cast<CustomEventType2*>(pEvent);
                doSomething(pCustomEventType2);
            }
            else {
                printf("Wrong Event Type in CustomModuleType2::receiveEvent\n");
            }
        };
};

int main(int argc, char** argv)
{
    CustomEventType1* pCustomEventType1 = new CustomEventType1();
    CustomEventType2* pCustomEventType2 = new CustomEventType2();

    BaseModule* arrModul[2];

    arrModul[0] = new CustomModuleType1();
    arrModul[1] = new CustomModuleType2();

    arrModul[0]->receiveEvent(pCustomEventType1);
    arrModul[0]->receiveEvent(pCustomEventType2);

    arrModul[1]->receiveEvent(pCustomEventType1);
    arrModul[1]->receiveEvent(pCustomEventType2);

	return 0;
}

it returns:
CustomModuleType1::doSomething function called
Wrong Event Type in CustomModuleType1::receiveEvent
Wrong Event Type in CustomModuleType2::receiveEvent
CustomModuleType2::doSomething function called

Anyone who can help me with this architecture problem ? It would be greatly appreciate !

I think you should check out the Command pattern.
In your case this means adding an Execute() method to your BaseEvent class. In the derived event classes you will code the Execute() method to call a virtual method in the Module class.
You send the Event (Command) to a Module (Receiver) and allow the Module to call the Execute() method on the Event.

There will be other solutions but I think this pattern can fit nicely.
Have a read and see what you think.

Thanks MrSpigot,

The command design pattern is really something related to this purpose. I did a kind of that in the following code but it is more based on callback functions :

#include <stdio.h>
#include <typeinfo>
#include <vector>
#include <utility>

using namespace std;

class CustomEventType1
{   
};

class CustomEventType2
{
};

class BaseModule
{
    public:
        virtual void sendEvent(){};
};

class CustomModuleType1:public BaseModule
{
    public:
        CustomModuleType1() {};

        void setCallBack(BaseModule* pModule, void (*functionPtr) (BaseModule*, CustomEventType1*) ) {_vCallBack.push_back( pair < void (*) (BaseModule*, CustomEventType1*), BaseModule*> (functionPtr, pModule));};

        vector<pair< void (*) (BaseModule*, CustomEventType1*), BaseModule*> > _vCallBack;

        virtual void sendEvent() {
            if (!_vCallBack.empty()) {
                for (unsigned int IDCallback=0; IDCallback<_vCallBack.size(); ++IDCallback) {
                    if (_vCallBack[IDCallback].second != NULL) {
                        (_vCallBack[IDCallback].first)(_vCallBack[IDCallback].second, new CustomEventType1());
                    }
                }
            }
        };

        void doSomething(CustomEventType2* pEvent) {
            printf("CustomModuleType1::receiveEvent function called\n");
        }

        static void receiveEvent(BaseModule* pModule, CustomEventType2* pEvent) {
            CustomModuleType1* pCustomModuleType1 = static_cast<CustomModuleType1*>(pModule);
            if (pCustomModuleType1) {
                pCustomModuleType1->doSomething(pEvent);
            }
        };
        
};

class CustomModuleType2:public BaseModule
{
    public:
        CustomModuleType2() {};

        void setCallBack(BaseModule* pModule, void (*functionPtr) (BaseModule*, CustomEventType2*) ) {_vCallBack.push_back( pair < void (*) (BaseModule*, CustomEventType2*), BaseModule*> (functionPtr, pModule));};

        vector<pair< void (*) (BaseModule*, CustomEventType2*), BaseModule*> > _vCallBack;

        virtual void sendEvent() {
            if (!_vCallBack.empty()) {
                for (unsigned int IDCallback=0; IDCallback<_vCallBack.size(); ++IDCallback) {
                    if (_vCallBack[IDCallback].second != NULL) {
                        (_vCallBack[IDCallback].first)(_vCallBack[IDCallback].second, new CustomEventType2());
                    }
                }
            }
        };

        void doSomething(CustomEventType1* pEvent) {
            printf("CustomModuleType2::receiveEvent function called\n");
        }
        
        static void receiveEvent(BaseModule* pModule, CustomEventType1* pEvent) {
            CustomModuleType2* pCustomModuleType2 = static_cast<CustomModuleType2*>(pModule);
            if (pCustomModuleType2) {
                pCustomModuleType2->doSomething(pEvent);
            }
        };
};

int main(int argc, char** argv)
{

    CustomModuleType1* pCustomModuleType1 = new CustomModuleType1();
    CustomModuleType2* pCustomModuleType2 = new CustomModuleType2();

    pCustomModuleType1->setCallBack(pCustomModuleType2, CustomModuleType2::receiveEvent );
    pCustomModuleType2->setCallBack(pCustomModuleType1, CustomModuleType1::receiveEvent );
    
    BaseModule* pModule1 = pCustomModuleType1;
    pModule1->sendEvent();

    BaseModule* pModule2 = pCustomModuleType2;
    pModule2->sendEvent();

	return 0;
}

I think that it is a bit nicer compare to the first solution but the use of function pointer make the code a bit more difficult to understand. I still need a downcast but now it is on module pointers.

Actually, I think that the QT library already solved this issue with its signal/slot mechanism. I wanted to avoid this because I think that the code become less clear with everything connected to everything but this presented solution is not clear too. So I think I will use QT.

This question has already been answered. Start a new discussion instead.