I’m trying to write a message processing thingy. The main components are a receiver, a processor, a filter, a translator and a sender. I would like to have a single point of failure at the “process” function of the processor component, for catching exceptions, logging and metrics.
Directly below is the console output, showing the bit of over-riding I am getting wrong.
BASE
A
B
A
---FILTER---
FILTERED BASE
DID NOT FILTER A
Looks like a B <------THIS IS WHAT I WANT
DID NOT FILTER B
---PROCESS---
FILTERED BASE
DID NOT FILTER A
DID NOT FILTER B <-----THIS MAKES ME SAD
These are the class definitions
#include <string>
#include <iostream>
#include <memory>
//**************MESSAGES ************************
class Message
{
public:
virtual std::string getOut() const {return std::string("BASE");};
};
class MsgA : public Message
{
public:
std::string getOut() const {return std::string("A");};
};
class MsgB : public Message
{
public:
std::string getOut() const {return std::string("B");};
};
//**************FILTERS ************************
class MsgFilter
{
public:
void filter(const std::tr1::shared_ptr<Message> msg)
{
if( msg->getOut().compare("BASE") == 0 )
{
std::cout << "FILTERED BASE" << std::endl;
}
else
{
std::cout << "DID NOT FILTER " << msg->getOut() << std::endl;
}
}
void filter(const std::tr1::shared_ptr<MsgB> msg)
{
std::cout << "Looks like a B" << std::endl;
filter((std::tr1::shared_ptr<Message>)msg);
}
};
//**************PROCESSORS ************************
class MsgProcessor
{
public:
MsgProcessor():myFilt(MsgFilter()){}
MsgFilter myFilt;
virtual void process(std::tr1::shared_ptr<Message> msg)
{
myFilt.filter(msg);
}
};
Below is the main function
#include "AllClassDefs.h"
int main(int argc, char *argv[])
{
std::tr1::shared_ptr<Message> msg(new Message());
std::tr1::shared_ptr<MsgA> msgA(new MsgA());
std::tr1::shared_ptr<MsgB> msgB(new MsgB());
std::cout << msg->getOut() << std::endl;
std::cout << msgA->getOut() << std::endl;
std::cout << msgB->getOut() << std::endl;
std::tr1::shared_ptr<Message> msgAPtr(msgA);
std::cout << msgAPtr->getOut() << std::endl;
std::cout <<"\n\nFILTER---\n";
std::tr1::shared_ptr<MsgFilter> flt(new MsgFilter());
flt->filter(msg);
flt->filter( (std::tr1::shared_ptr<Message>) msgA);
flt->filter(msgB);
std::cout <<"\n\nPROCESS---\n";
std::tr1::shared_ptr<MsgProcessor> prc(new MsgProcessor());
prc->process(msg);
prc->process(msgA);
prc->process(msgB);
}
So… I want the process function to call the Filter(MsgB) function and not the Filter(Message) function. By using the process(Message) function it looks like Filter treats the MsgB as a Message regardless. How can I make it work nicely?
I know I could use templates, but that seems a bit over overkill… plus in a system with a couple of hundred messages classes it might lead to a big exe. Should I use double dispatch? Or is there an easier solution to this?
Your problem is that overload resolution is performed at compile time, so this function
will always call the same overload
because that matches the static type of the parameter.
It doesn’t matter if
msgsometimes happens to point to a derive class.