Grouping Unrelated Stuff in C++

Started by
5 comments, last by mako_5 17 years, 7 months ago
I'm trying to make a system in a single player text based game where you would give an object (like a player) a script and any parameters. The problem is I don't know how to pass multiple unknown types as a group in C++. Here's how I would do it in Java:

void runScript(String str, Object[] params){
  //not the best example, but hopefully communicates what I'm trying to do
  if(str.equals("buy")
  {
    if(params[0] instanceof Merchant)
    {
       // run a function for trading
       ((Merchant)params[0]).tradeWith(this);
    }
  }
}
Could anyone give me suggestions, or another way to do this? Thank you for your time and assistance.
Advertisement
Check into boost::variant or, in more extreme cases, boost::any.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by mako_5
The problem is I don't know how to pass multiple unknown types as a group in C++.


If the types are completely unknown, you are more or less hosed, although you can follow ApochPiQ suggestion as a possible fix.

Quote:Here's how I would do it in Java


It works in Java because all objects have a common base class. Such a design can be duplicated in C++ using a container of pointers to a common base class of the parameters you're going to use. Please note that pointers are necessary. Since you come from a Java background, boost::shared_ptr may be useful to approximate the behaviour of Java references.

Quote:
if(params[0] instanceof Merchant)


Capability queries can be a sign of poor design. Prefer calling common virtual member functions whenever possible.

Quote:Could anyone give me suggestions, or another way to do this?


Here is the code that most closely duplicates your Java approach. Think twice before using it. If you can you tell us more about your system, we might be able to give you a better solution.


void runScript(const std::string& str, const std::vector<Object*>& params){  if(str == "buy")  {    if( Merchant* m = dynamic_cast<Merchant*>(params[0]) )    {       m->tradeWith(*this);    }  }}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
What I was trying to do, was to make objects communicate through a general object passing system. All of these events or actions (whatever you want to call them), get handled in this order:

1:Characters / Items in rooms
2:Rooms
3:Locales (groups of rooms)
4:World

An unhandled event bubbles up to the next level of command:
unhandled character scripts get sent up to rooms, which if cannot handle send them to locales and finally to the world.

This prevents each of these components from being required to know directly about any other object. In an asteroids game (Java) I made, an object could request an explosion by sending an object like this to be collected by the script handler...

new GameEvent("particle system",new Object[]{"explosion",new Point(x,y)});


When the script system would loop through to find events objects want carried out, it takes this event and sends it to the destination object (the event collector has previously mapped strings to objects that can receive these generic commands).

The target, "particle system" then takes the command, interprets it, and then executes it if possible.

Perhaps using inheritance would be a better idea (like you mentioned virtual)...?
e.g.

//abstract base class
class ICommand{
public:
ICommand(const std::string& destination_){destination = destination_};
~ICommand(){};
virtual void execute()=0;

private;
std::string destination;
};


class MakeExplosionCommand{
public:
MakeExplosionCommand(const std::string& std::string destination, float locX, float locY);
//etc...
///*virtual*/ provided to remind programmer that yeah, it's virtual
/*virtual*/ void execute();
};
Quote:Original post by Fruny
Capability queries can be a sign of poor design. Prefer calling common virtual member functions whenever possible.


Agreed. Good polymorphism is almost always better design than if statements.
Quote:Original post by mako_5
An unhandled event bubbles up to the next level of command:
unhandled character scripts get sent up to rooms, which if cannot handle send them to locales and finally to the world.


So you have something like a Chain of Responsibility pattern.

Quote:When the script system would loop through to find events objects want carried out, it takes this event and sends it to the destination object (the event collector has previously mapped strings to objects that can receive these generic commands).


Then I think you are looking from the wrong end of the problem. Typically, an object knows what kind of events it is able to handle, rather than having an event know what kind of objects it can be handled by.

Quote:The target, "particle system" then takes the command, interprets it, and then executes it if possible.


See above. In your example, you should ask the target object to handle a "buy" event, rather than ask it whether it is a Merchant.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
See above. In your example, you should ask the target object to handle a "buy" event, rather than ask it whether it is a Merchant.


Thanks for the help Fruny. I now see exactly what you're talking about. I'll get started on the event hierarchy now...

This topic is closed to new replies.

Advertisement