oop - C++ Design: Overloading/Overriding many many functions, way to clean up? -
the case trying implement here base class has function (let's call modify_command) can accept many different types virtually derived classes can implement modify_command function see fit. right have along these lines in base class:
class base { template<typename command> void modify_command(command cmd) { std::cout << "modify command called unimplemented command type:" << typeid(cmd).name(); } virtual void modify_command(specificcommanda cmd) { modify_command<specificcommanda>(cmd); // calls templated function } virtual void modify_command(specificcommandb cmd) { modify_command<specificcommandb>(cmd); // calls templated function } // etc. };
then in derived class:
class derived : public base { virtual void modify_command(specificcommanda cmd) { cmd.x = 1; cmd.y = 2; } }
obviously virtual template function isn't possibility in form going have list function declarations umpteen many argument possibilities sure clutter class definition , may make difficult (over time) additional command types handled
the purpose of having templated function case compile without needing definition of modify_command(specificcommandc) log error:
base * base = new derived(); specificcommanda a; specificcommandb b; specificcommandc c; base->modify_command(a); //set's x , y base->modify_command(b); //outputs command type unimplemented base->modify_command(c); //outputs command type unimplemented
i hate how have working, have suggestion on how can cleaned / reimplemented? number of commands continue grow software matures, extensibility must.
edit: grammar
unfortunately, solve problem virtual template method, not possible.
here more c-ish solution brought c++ world can work around limitation:
#include<unordered_map> #include<functional> #include<memory> #include<iostream> #include<utility> struct basecommand { static int counter; }; int basecommand::counter = 0; template<class t> struct command: basecommand { static int type() { static const int t = ++counter; return t; } }; struct specificcommand1: command<specificcommand1> {}; struct specificcommand2: command<specificcommand2> {}; class base { struct handler { virtual void operator()(basecommand &cmd) = 0; }; template<typename t> struct thandler: handler { std::function<void(t)> func; void operator()(basecommand &cmd) override { func(static_cast<t&>(cmd)); } }; protected: template<typename t> void assign(std::function<void(t)> f) { auto handler = std::make_unique<thandler<t>>(); handler->func = f; handlers[t::type()] = std::move(handler); } public: template<typename command> void modifycommand(command cmd) { auto = handlers.find(command::type()); if(it == handlers.end()) { std::cout << "modify command called unimplemented command type: " << command::type(); } else { auto &h = *(it->second); h(cmd); } } private: std::unordered_map<int, std::unique_ptr<handler>> handlers; }; class derived: public base { public: derived() { std::function<void(specificcommand1)> f = [](specificcommand1) { std::cout << "handler specificcommand1" << std::endl; }; assign(f); } }; int main() { base *b = new derived; b->modifycommand(specificcommand1{}); b->modifycommand(specificcommand2{}); }
the basic idea give numeric type @ runtime commands (it can done crtp idiom - see basecommand
, command
template class).
value accessible, it's matter of creating type-erased handler deal commands want provide specific implementation (see assign
, handler
/thandler
).
once have pieces correctly set, have design , initialize handlers in derived classes. can done using std::function
, can use handler lambda, public or private member method, static method , on.
see constructor of derived
further details.
Comments
Post a Comment