Multiple purposes for a function in c++

Started by
5 comments, last by Fruny 17 years, 5 months ago
I have a class, (module; it describes a module in a spaceship) and I'm making each module able to ahve a specific action(). the action can do several different things. It can fire a weapon, engage the engines, smelt some ore, or any number of things. not all of these functions require the same types of arguments. Is there any way I can generically pass arguments to the function, so that I can give coordinates to a gun, and a magnitude to a engine?
Advertisement
No, but there are a variety of design patterns around this sort of specific problem; the interpreter strikes me as the first I'd look into.
One word.... Abstract base class.

class ActionArgs{    // code here};class Module{public:    virtual void Action(ActionArgs * pArgs) throw() = 0;};class EngineArgs : public ActionArgs{    // code here};class Engine : public Module{public:    virtual void Action(ActionArgs * pArgs) throw()    {        EngineArgs * pEngineArgs = dynamic_cast<EngineArgs *>(pArgs);        // do your code with pEngineArgs    }};
There are ways to do it, and there are better ways to do it, and there is probably an even better way to solve your problem without doing it. Since the calling code knows what kind of parameters to provide, it must also know the class and member function that it is calling. Why then must the parameters be in a generic form?
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by NIm
I have a class, (module; it describes a module in a spaceship) and I'm making each module able to ahve a specific action(). the action can do several different things. It can fire a weapon, engage the engines, smelt some ore, or any number of things. not all of these functions require the same types of arguments. Is there any way I can generically pass arguments to the function, so that I can give coordinates to a gun, and a magnitude to a engine?


it's hard to properly answer your question without having had a look into your current design, and without knowing how much of your existing design must remain unaltered, however in general there are really many ways to accomplish this, some of which are more invasive than others, for example:


- you could simply override your action methods for each individual type of action, as long as the method signatures are different, there should be no problems:
class CSpaceShipModule { void action(coordinates& c); void action(magnittude& m); void action(direction& d); void action(force& f);};


In general however, it should be considered bad style to implement multiple identically-named functions that serve completely different purposes, without making the purpose more obvious-be it by naming the action properly in the first place, or by providing a corresponding "mode" flag:
class CSpaceShipModule {public:enum action_mode {FIRE,ENGAGE,ORE};void action(action_mode m, parameterContainer& pC) {}private:};



- you could also define object-specific global functions that implement your actions:

void fire(const CSpaceshipModule& s) {}void engageEngine(const CSpaceModule& s) {}


So, basically what I am saying: you may want to reconsider your current design and provide some background info about it, so that we can also provide more informed advice.
This striked me as a good design:
class Container {public:  float getSomeFuel(float pHowMuch) {    if( mFuel < pHowMuch ) {      float fuel = mFuel;      mFuel = 0.0f;      return fuel;    }    return   }  void fill(float pHowMuch) {    mFuel += pHowMuch;  }private:  float mFuel;};class EngineModule : public Module {public:  void action() {    float fuel = mFuelContainer->getSomeFuel(1.0f);    thrust(fuel);  }  void setFuelContainer(Container* pConatiner) {mFuelContainer = pContainer;}private:  Container* mFuelContainer;};// The gun works the same way since it only fires in one directionclass MelterModule {public:  void setInContainer(Container* pConatiner) {mInContainer = pContainer;}  void setOutContainer(Container* pConatiner) {mOutContainer = pContainer;}  void action() {    mOutContainer.fill( mInContainer.getSomeFuel(1.0f) );  }private:  Container* mInContainer;  Container* mOutContainer;};


If you need more control over how you should control the modules you need a different interface.
Quote:Original post by NIm
Is there any way I can generically pass arguments to the function, so that I can give coordinates to a gun, and a magnitude to a engine?


Not directly, no. Your compiler will demand that you pass the right number and type of parameters to any function you call, as specified by their signatures, which are checked at compile time. Unless you encode all the possible parameters into a common type (e.g. a string), and are ready to have each function explicitely unpack its parameters and check them for correctness (see here for some ideas), you will not be able to treat them polymorphically.
"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

This topic is closed to new replies.

Advertisement