I am creating an application whose use would look something like this:
application --command --option1=? --option2=2?
In principle, there can be any number of options, but only one command per application instance. Similar to how git works.
Now I thought that I would write it in C ++ in order to get some momentum and experience with STL, and go with some of those design patterns that I continue to read about. So, I implemented this:
class Action { public: void AddParameter(std::string key, boost::any p); virtual unsigned int ExecuteAction(); protected: std::map<std::string, boost::any> parameters; };
Iβll explain my logic anyway, just to test it out is an abstract action. All actions need to add a parameter, so the parameter map is for us to implement at this level, but we expect ExecuteAction be implemented by derived classes, such as my simple DisplayHelpAction example, which does pretty much what it says about tin.
So now I wrote a factory, for example:
class DetermineAction { public: DetermineAction(); vx::modero::Action getAction(std::string ActionString); private: std::map<std::string, vx::modero::Action> cmdmap; };
The logic is that the constructor will create a map of possible strings that you can request, and getAction will do what it says - give it a command line, and it will give you a class derived from Action that implements the desired functionality.
I am having problems with this constructor. I try this:
this->cmdmap = std::map<std::string, Action>(); this->cmdmap.insert(pair<string, Action>("help", DisplayHelpAction())); this->cmdmap.insert(pair<string, Action>("license", DisplayLicenseAction()));
This causes a lot of errors. Now I'm used to the Java Way interface, so you use:
Interface I = new ConcreteClass();
and Java like it. So the idea I'm trying to achieve here is because what I want to do to implement getAction is this:
return this->cmdmap[ActionString];
To whom should I return the class obtained from Action, after which I can start adding parameters and invoking execution.
So, to summarize, I have two questions that are closely related:
- Soundboard. I deliberately abstract things, so there is some additional complexity, but in principle, does my approach sound? Is there an insanely obvious shortcut that I missed? Is there a better method I should use?
How do I configure a solution for class mapping so that I can return the correct class? A specific complaint is link time and:
Linking CXX executable myapp CMakeFiles/myapp.dir/abstractcmd.cpp.o: In function `nf::Action::Action()': abstractcmd.cpp:(.text._ZN2vx6modero6ActionC2Ev[_ZN2vx6modero6ActionC5Ev]+0x13): undefined reference to `vtable for nf::Action'
Just because it might be relevant, I use boost::program_options to parse the command line.
Edit 1 : Ok, now I replaced Action with Action* according to Eugene's answer and am trying to add new SomethingThatSubclassesAction to the map. I am still getting vtable error.