tags:

views:

105

answers:

5
class Message {};
class BuildSandCastle : public Message {};
class DigHole : public Message {};

Given an arbitrary Message* object, how can I call a function of the same name doMessage() without resorting to switch logic or making a MessageHandler class that has one 'do' function for every message name?

EDIT: for example:

class Sandbox
{
public:
  void play(Message* m)
  {
     // call doBuildSandCastle
     // or doDigHole based on m's type
  }
  void doBuildSandCastle();
  void doDigHole();
};

Sorry I wasn't clear before.

EDIT:

can someone just delete this train wreck of a question? I really don't want all these highschool lessons in polymorphism.

A: 

Use virtual functions.

class Message {
  virtual void doSomething(...) = 0;
};

class ReportMessage : public Message {
  virtual void doSomething(...) {
  // (...) - specific for repors
  }
};

class BankReportMessage : public ReportMessage {
  virtual void doSomething(...) {
  // (...) -||- for banks
  }
};

Now, somewhere in your code:

Message* my_message = new BankReportMessage(...);
my_message->doSomething(...); // Would call appropriate function
Kotti
A: 

Sounds like homework, so you should probably look at virtual functions (wikipedia). Message should probably have pure virtual doMessage, which gets overridden in the subclasses.

Stephen
+8  A: 

EDIT: Now that the question has been clarified, here is the new answer:

You can either get your message object to call the right function:

void play(Message* m) { m->play(this); } 

or you could have a map of function pointers in Sandbox and execute the appropriate function based on the message name (or typeid), e.g.

handler_map[m.name()]();

I would use Boost::function to store function pointers in a map.


OLD ANSWER: I think what you need is virtual functions:

class Message 
{
  virtual void doMessage { std::cout << "message" << std::endl; }
};
class BuildSandCastle : public Message 
{
  virtual void doMessage { std::cout << "build sand castle" << std::endl; }
};
class BuildSandCastle : public Message 
{
  virtual void doMessage { std::cout << "dig hole" << std::endl; }
};

When you call doMessage like this:

Message* msg = new BuildSandCastle();
msg->doMessage();

it will output "build sand castle".

Alex - Aotea Studios
+2  A: 

It sounds like you are just trying to add a polymorphic function to some classes. Assuming any parameters and return values are the same on the sub classes, you can add a pure virtual function to the base class.

eg : (note: I didn't compile this, so apologies if there are typos)

class Message
{
    public:
    virtual void doMessage() = 0;
};

class BuildSandCaste : public Message
{
    public:
    void doMessage() { /* build a sand castle */ }
};

class DigHole : public Message
{
    public:
    void doMessage() { /* dig hole */ }
};
Phil Young
It's usually a good practice to put `virtual` before every function declaration (not only in the base class), so that somebody who inspects your interface can easily distinguish `virtual` and `non-virtual` methods.
Kotti
A: 

I was looking for something like this

class MessageHandlerBase
{};

template<typename MessageType>
class MessageHandler:
    public virtual MessageHandlerBase
{
    virtual void process(MessageType*)=0;
};

class Message
{
protected:
    template<typename MessageType>
    void dynamicDispatch(MessageHandlerBase* handler,MessageType* self)
    {
        dynamic_cast<MessageHandler<MessageType>&>(*handler).process(self);
    }
};
class Message1:
    public MessageBase
{
    void dispatch(MessageHandlerBase* handler)
    {
        dynamicDispatch(handler,this);
    }
};

Except without having to use dynamic_cast, or passing the message itself (a la the code in the original question.)

Kyle