Creating Command objects at run-time - c++

I'm trying to write a console for a game engine which will allow me to type in commands to perform tasks, such as change the map, spawn an enemy etc.
I've been trying to do this with the Command pattern (following the example from gameprogrammingpatterns.com). See below for the outline of my current code structure.
parseCommand processes the string from the user, extracting the command name and arguments (currently using just whitespace separation). The next step is where I'm stuck. I need to create a Command* somehow to call execute on but I only have the string name of the command.
I could have a giant bunch of if statements in my parseCommand function, such as:
if (cmdName == "spawn")
return new SpawnEnemyCommand();
Alternatively I could store a pointer to each command in myConsole class, e.g. Command *spawnNewEnemy = new SpawnNewEnemy(); and then in parseCommand do if (cmdName == "spawn") spawnNewEnemy->execute();. This second option seems to be how the gameprogrammingpatterns book does it.
Neither of these options seems very practical if I end up with hundreds of console commands. I've studied all the articles and posts I can find on this pattern but it isn't helping clarify the situation for me.
How can I cleanly instantiate the correct Command object from within parseCommand?
Command interface base class:
class Command {
public:
virtual ~Command() { }
virtual void execute() = 0;
};
Example interface implementation:
class SpawnEnemyCommand : public Command {
public:
void execute() {
// method calls to perform command go here
}
};
Console class header:
class Console {
public:
Command* parseCommand(std::string);
bool validateCommand(std::string, std::vector<std::string>);
};

By relying on a dictionary (e.g, std::unordered_map or std::map) that maps a command identifier (i.e., a std::string object) to a Command object, you can design a factory with dynamic registry for your Command objects.
First, extend Command by including another virtual member function, clone(), that allows us to implement The Prototype Pattern:
class Command {
public:
// ...
virtual std::unique_ptr<Command> clone() const = 0;
};
The clone() virtual member function does what its name suggests: it clones the object. That is, SpawnEnemyCommand would override Command::clone() in the following way:
class SpawnEnemyCommand : public Command {
public:
// ...
std::unique_ptr<Command> clone() const override {
// simply create a copy of itself
return std::make_unique<SpawnEnemyCommand>(*this);
}
};
This way, your command objects can be copied polymorphically through the Command interface – i.e., you don't need to know the concrete type of the command to be copied. All you need to do to copy a Command object is to call its clone() virtual member function. For example, the following function copies the Command passed as an argument regardless of the underlying concrete type:
std::unique_ptr<Command> CopyCommand(const Command& cmd) {
return cmd.clone();
}
With this in mind, you are ready to design a factory for command objects, CommandFactory, that supports dynamically registering your command objects:
class CommandFactory {
public:
void registerCommand(std::string id, std::unique_ptr<Command>);
std::unique_ptr<Command> createCommand(std::string id) const;
private:
std::unordered_map<std::string, std::unique_ptr<Command>> registry_;
};
It all boils down to a std::unordered_map<std::string, std::unique_ptr<Command>> data member. Indexing this data member by a command identifier, which is an std::string, we retrieve a Command object – This is the prototype object we will use for cloning.
The registerCommand() member function adds a Command prototype to the registry:
void CommandFactory::registerCommand(std::string cmdId, std::unique_ptr<Command> cmd) {
registry_[cmdId] = std::move(cmd);
}
The createCommand() member function clones the Command prototype corresponding to the requested command identifier:
std::unique_ptr<Command> CommandFactory::createCommand(std::string cmdId) const {
auto const it = registry_.find(cmdId);
if (it == registry_.end())
return nullptr; // no such a command in the registry
auto const& cmdPtr = it->second;
return cmdPtr->clone();
}
As an example program:
auto main() -> int {
CommandFactory factory;
factory.registerCommand("spawn", std::make_unique<SpawnEnemyCommand>());
// ...
auto cmdPtr = factory.createCommand("spawn");
cmdPtr->execute();
}
You can also extend this factory to add support for dynamically deregistering your already-registered Command prototypes.

Related

Going around in circles with Pure Virtual Functions

I am using a simple inheritance structure to try and simplify code structure and reduce common code usage across a number of classes.
The idea is to allow a simple linked list structure within the class to allow the entire set of instances to be iterated.
EDIT:
To elaborate, this is intended to support a bunch of classes that can be aggregated by type and then iterated by type. Hence the decision to use a linked list with a static "first member" held in the class.
The actual application is support classes for switches, buttons, lights, parsers inside an embedded platform (Arduino).
When I create 20 switch instances of cSwitch (for instance)
cSwitch cSwitchA(_pin,callback);
cSwitch cSwitchB(_pin,callback);
I can then use
loop() {
cSwitch::checkAll();
}
inside my "loop" function, rather than having to do:
void loop() {
cSwitchA::check();
cSwitchB::check();
...
}
...
extending this to other classes, I can do:
loop() {
cSwitch::checkAll();
cLight::checkAll();
cParser::checkAll();
}
all of the members are declared with pins, parameters and callback functions.
I think that the problem is not specific to Arduino, but a little more abstract in that it could probably arise in any similar scenario.
class cGroup {
public:
cGroup(){cGroup::register_instance(this);}
~cGroup();
static void register_instance(cGroup * _inst) {
cGroup pInstance=nullptr;
if (_inst->getFirstInstance()==nullptr) {
_inst->setFirstInstance(_inst);
return;
} else {
pInstance=_inst->getFirstInstance();
}
while (1) {
if (pInstance->getNextInstance() == nullptr) {
pInstance->setNextInstance(_inst);
return;
} else {
pInstance=_inst->getNextInstance();
}
}
}
static void checkAll(cGroup * firstInstance);
virtual cGroup* getFirstInstance()=0;
virtual void setFirstInstance(cGroup*)=0;
};
class cMemberA: public cGroup {
public:
cMemberA():cGroup(){}
static void checkAll() {cGroup::checkAll(cMemberA::firstInstance);}
static cGroup * _firstInstance;
cGroup* getFirstInstance() {return cMemberA::firstInstance;}
void setFirstInstance(cGroup* _firstInstance){cMemberA::firstInstance = _firstInstance;}
};
cGroup * cMemberA::_firstInstance = nullptr;
class cMemberB: public cGroup {
... etc
};
The main need to do it this way stems from the fact that if I push the static "firstInstance" variable up into the cGroup class, it only allows for one long list containing many different types of Member classes. What I want is one list per type of Member class, meaning that I need to scope the static "firstInstance" variable into the Member class itself.
The problem I am finding is that I am going around in circles trying to figure out how to invoke getFirstInstance() and setFirstInstance from within the member class while only having a cGroup* pointer to play with.
If I have pure virtual classes inside of cGroup with cGroup * declarations, then these are not satisfied by declarations in the subclass of cMemberA * (and cMemberB *, cMemberC etc...)
declaring the "first-instance" members as "cMemberA*" leads to compilation issues (abstract class), but declaring them as cGroup* leads to an inability to invoke the required members in the cMemberA instances.
Is there another way to do this, or am I fundamentally going about this the wrong way? Please be gentle, it's been about 10 years since my last rodeo with C++ and I'm not a professional programmer.
Of course I can get around this issue by dispensing with cGroup entirely and just putting everything into cMemberA, cMemberB etc. but then that's where I was last week and as far as I recall, that's not the best way with C++ as the whole idea is to reduce code duplication.
The code you posted does have a problem, but I think it's different from the ones you mentioned.
The problem I see is that you call register_instance from the cGroup constructor, and then call virtual functions, eg. getFirstInstance() from that. Virtual calls don't work as expected at construction time (because the vtable isn't properly initialized yet). Basically you need to construct your object first, and you can call register once the object is fully constructed, in a second step.
The usual way around this would be to use a factory function instead of directly the constructors. The factory function would first create a new instance, then register that fully created instance, then return it. BUT, your factory function would need to create the instance on heap and return a pointer (if it returned by value, then it would register an instance, return a copy of it, then destruct the registered instance). Usually this isn't a problem, types with virtual functions are usually used as reference types (not value types) anyway, but in your particular embedded case that may be a problem.
Another way is to create intermediate classes between cGroup and cMemberX, eg. cMemberA: cMemberABase: cGroup. first_instance and getFirstIntsnace() etc. would be defined in cMemberABase. Then cMemberA's constructor could call cGroup::register, because by that time the vtable for cMemberABase is already constructed (but not yet for cMemberA!). In other words, when in the subclass constructor, the base subobject's virtuals can already be used, but not the virtuals defined in the subclass.
class cGroup {
protected:
cGroup(){}
public:
template <class G> static G* make() {
G* instance = new G();
cGroup::register_instance(instance);
return instance;
}
~cGroup() {}
static void register_instance(cGroup * _inst) {
cGroup* pInstance=nullptr;
if (_inst->getFirstInstance()==nullptr) {
_inst->setFirstInstance(_inst);
return;
} else {
pInstance=_inst->getFirstInstance();
}
while (1) {
if (pInstance->getNextInstance() == nullptr) {
pInstance->setNextInstance(_inst);
return;
} else {
pInstance=_inst->getNextInstance();
}
}
}
static void checkAll(cGroup * firstInstance) {
}
virtual cGroup* getFirstInstance()=0;
virtual void setFirstInstance(cGroup*)=0;
cGroup* getNextInstance() { return nextInstance; }
void setNextInstance(cGroup* nextInstance) { this->nextInstance = nextInstance; }
cGroup* nextInstance = nullptr;
};
class cMemberABase: public cGroup {
protected:
friend class cGroup;
cMemberABase():cGroup(){}
public:
static void checkAll() {cGroup::checkAll(cMemberABase::firstInstance);}
static cGroup * firstInstance;
cGroup* getFirstInstance() {return cMemberABase::firstInstance;}
void setFirstInstance(cGroup* _firstInstance){cMemberABase::firstInstance = _firstInstance;}
};
cGroup* cMemberABase::firstInstance = nullptr;
class cMemberBBase: public cGroup {
protected:
friend class cGroup;
cMemberBBase():cGroup(){}
public:
static void checkAll() {cGroup::checkAll(cMemberBBase::firstInstance);}
static cGroup * firstInstance;
cGroup* getFirstInstance() {return cMemberBBase::firstInstance;}
void setFirstInstance(cGroup* _firstInstance){cMemberBBase::firstInstance = _firstInstance;}
};
cGroup* cMemberBBase::firstInstance = nullptr;
class cMemberA: cMemberABase {
public:
cMemberA(): cMemberABase() {
cGroup::register_instance(this);
}
};
class cMemberB: cMemberBBase {
public:
cMemberB(): cMemberBBase() {
cGroup::register_instance(this);
}
};
It is much simpler and idiomatic to let the outer code organize objects into containers as needed:
cSwitch cSwitches[2] = {{_pin,callback}, {_pin,callback}};
loop() {
for (auto& switch : cSwitches)
switch.check();
}
If you want "names" for the elements, add an enum:
enum cSwitchNames { A, B, count };
cSwitches[A].check(); // if you need to check just one

Calling a derived class method from the parent class' same method

My problem goes as follow: I am writing an extensible communication protocol between a server and a client. The objects needed to be transferred are using the command design pattern.
Here is the class format:
class command {
public:
using id = uint8_t;
using buffer = std::vector<char>;
enum command_t: id {a_command, another_command};
command() = delete;
command(id id): id_(id) {}
static command* unserialize(buffer);
virtual buffer const serialize() const = 0;
virtual void execute() = 0;
protected:
/* Not possible, see further where I explain. Keeping it here for
my example */
virtual static command* do_unserialize(buffer::iterator, buffer::iterator) = 0;
id id_;
};
class a_command;
class another_command;
Every command will be a subclass of command. A command_t id will be associated with every command. In the example above, a_command and another_command would have a respective class too.
command::serialize is implemented in the derived classes. What it does is it writes all the needed informations of the class in a byte array and returns it. Of course, the same thing goes for the protected command::do_unserialize - it takes a byte array and converts it to a command of the right type. But here is the problem:
The first byte of the buffer will always be the command::id associated with the good subclass.
When the server/client will receive data, it will read the command ID and then it needs to be able to unserialize it to the right command type. This is why it will need to call the static function command::unserialize and not one of the subclasses' do_unserialize.
A quick and dirty fix would be a command::unserialize looking like this:
command* command::unserialize(buffer b) {
auto it{b.begin()};
command::id const id{*it++};
switch(static_cast<command::command_t>(id)) {
case command::command_t::a_command:
return a_command::do_unserialize(it, b.end());
case command::command_t::another_command:
return another_command::do_unserialize(it, b.end());
default:
throw std::invalid_argument("command::unserialize: unknown command ID");
}
}
*** Actually not even, you cannot have a virtual static member function. So I have no idea how it could be implemented.
Even if it worked, it is not really fun, because it implies having to duplicate a line of code
for every new command created.
EDIT: A working example would be to move do_unserialize to the subclass constructor and return a pointer to the newly created object.
class derived_command: public command {
public:
derived_command(buffer::iterator beg, buffer::iterator end) {
// do_unserialize logic
}
};
// unserialize
switch (id) {
case command::command_t::derived_class: return new derived_class(b.begin(), b.end());
}
// ...
My question thus goes like this: Is there a way to dynamically link new commands only from the command::id field? A way to deduce the subclass to use from its ID? Else, is my design flawed? Is there a better way to do what I'm trying to do?
Thank you!

Working on a solid Command Pattern with shared_ptr

I am trying to implement a very clean Command Pattern in a library.
I have the following structure right now (a few parts are still being finished up):
users (client-code) have some Object, call it "Manager"
Manager holds a collection of shared_ptr<Foo>
Manager provides access to the collection by returning shared_ptr<Foo>
I have a Command abstract class and a hierarchy of commands for actions to perform on Foo
Client code should not call Command::execute(), only Manager should, Manager::execute(shared_ptr<Command>), so that it can handle undo/redo
I would like to follow the following rules:
users (client-code) have some Object, call it "Manager"
Manager holds a collection of shared_ptr<Foo>
Manager provides access to the collection by returning shared_ptr<const Foo>
I have a Command abstract class and a hierarchy of commands for actions to perform on Foo
Client code cannot (without workarounds) call Command::execute(), only Manager can, Manager::execute(shared_ptr<Command>), so that it can handle undo/redo and get non-const smart pointers
A Manager must be able to allow Command objects to access and modify shared_ptr<Foo> even though the user initializes Command objecst with shared_ptr<const Foo>
I am just trying to figure out the best way to handle giving out shared_ptr<const Foo> while allowing number 5 and 6 to work.
Is there any example/design pattern that does this which I could learn from? Is this a good idea compared to what I already have/am working on?
I think this passkey pattern should be the right thing for you:
class CommandExecuteKey{
private:
friend class Manager;
CommandExecuteKey(){}
};
class Command{
public:
// usual stuff
void execute(CommandExecuteKey);
};
class Manager{
public
void execute(Command& cmd){
// do whatever you need to do
cmd.execute(CommandExecuteKey());
}
};
Now, Command doesn't know anything about Manager, only about the key that is needed for the execute function. The user won't be able to call the execute method directly, as only Manager can create CommandExecuteKey objects, thanks to a private constructor and friendship.
int main(){
Command cmd;
Manager mgr;
//cmd.execute(CommandExecuteKey()); // error: constructor not accessible
mgr.execute(cmd); // works fine, Manager can create a key
}
Now, for your 6th point:
When you get the command in, search all your shared_ptr<Foo>s for the correct object (using the saved shared_ptr of the command as a search-key) and then pass that mutable one from your internal shared_ptrs back to the command.
Since it wouldn't make any sense to me otherwise, I'm going to assume that
your library provides the Manager class (or at least a base class), and
clients have to use that class to invoke a Command.
In that case, maybe something like this could work:
void Manager::execute(Command& cmd, shared_ptr<Foo const> const& target)
{
shared_ptr<Foo> mutableTarget = this->LookupMutableFoo(mutableTarget); // throws if not found
cmd.execute(mutableTarget); // client cannot invoke without mutable pointer
}
// or, if the "target" needs to be stored in the Command you could use something like this:
void Manager::execute(Command& cmd)
{
shared_ptr<Foo> mutableTarget = this->LookupMutableFoo(cmd.GetTarget()); // throws if not found
cmd.execute(mutableTarget); // client cannot invoke without mutable pointer
}
I'm not sure though if using const is the best solution here. Maybe you should wrap your Foo objects in e.g. ClientFoo objects. The manager only hands out pointers to ClientFoo. The manager can then (e.g. via friend) get the Foo from the ClientFoo, and use it to invoke the Command.
I'm not following your question 100%, but here goes...
The only thing I can think of for #5 is to make Command::execute private/protected and make Manager a friend of Command. The downside of this approach is that you've now introduced a dependency from Command to Manager.
As for #6, if the user's shared_ptr<const Foo> objects were originated from Manager's shared_ptr<Foo> collection, then Manager should be able to safely const_pointer_cast shared_ptr<const Foo*> back into shared_ptr<Foo*>. If Manager attempts to const cast a shared_ptr<const Foo*>, where the pointee is an actual constant object, you'll get undefined behavior.
I've thought of another solution for #5:
Define an ExecutableCommand class, derived from Command. ExecutableCommand has an added method to invoke the command, to be used only by Manager. Clients can only access ExecutableCommand objects via pointers/references to Command. When a Manager wants to invoke a Command, it downcasts it to a ExecutableCommand to gain access to the invocation interface.
Working example (including const_pointer_cast for #6):
#include <iostream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
//------------------------------------------------------------------------------
struct Foo
{
Foo(int x) : x(x) {}
void print() {++x; cout << "x = " << x << "\n";} // non-const
int x;
};
//------------------------------------------------------------------------------
struct Command
{
// Interface accessible to users
std::string name;
private:
virtual void execute() = 0;
};
//------------------------------------------------------------------------------
struct ExecutableCommand : public Command
{
// Only accessible to Manager
virtual void execute() {} // You may want to make this pure virtual
};
//------------------------------------------------------------------------------
struct PrintCommand : public ExecutableCommand
{
PrintCommand(shared_ptr<const Foo> foo)
: foo_( const_pointer_cast<Foo>(foo) ) {}
void execute() {foo_->print();}
private:
shared_ptr<Foo> foo_;
};
//------------------------------------------------------------------------------
struct Manager
{
void execute(Command& command)
{
ExecutableCommand& ecmd = dynamic_cast<ExecutableCommand&>(command);
ecmd.execute();
}
void addFoo(shared_ptr<Foo> foo) {fooVec.push_back(foo);}
shared_ptr<const Foo> getFoo(size_t index) {return fooVec.at(index);}
private:
std::vector< shared_ptr<Foo> > fooVec;
};
//------------------------------------------------------------------------------
int main()
{
Manager mgr;
mgr.addFoo( shared_ptr<Foo>(new Foo(41)) );
Command* print = new PrintCommand(mgr.getFoo(0));
// print.execute() // Not allowed
mgr.execute(*print);
delete print;
}

Singleton class whose ctor requires arguments

I have class Command which is an instance of a class EventManager. Class Command requires two arguments(host, target) in its constructor.
class EventManager
{
public:
void Event1(){ cmd->Execute(_eventEnum); }
private:
Command *cmd;
};
class Command
{
public:
Command(Host h, Target t)
void Execute();
private:
}
Now if i need to use this method cmd->Execute() in a member function of Target class, i need to make cmd an instance variable of Target or make it global as a singleton.
I cant make cmd an instance variable of Target because it doesn't take host instance. To make it a singleton would be to add two methods like this
class Command
{
public:
CreateInstance(Host h, Target t);
GetInstance();
void Execute();
private:
Command(Host h, Target t);
}
I need to make sure that GetInstance is called after CreateInstance. Any other alternative?
Target class is a low level class with few events.
Target::LowlevelEvent()
{
cmd->Execute(lowlevelevent) //In Execute for lowlevelevent in Command class, i might call target->reset
}
Iam sorry for not being able to explain clearly. The problem is, this code has lot of events(methods), which may be in classes like EventManager or Target.
In each of these event, i would have to call a Command->Execute(). The command class requires host and target instances because they can do certain actions.
EventManager::Event1()
{
cmd->Execute(_event1);
}
Target::Event2()
{
cmd->Execute(_event2);
}
Command::Execute(Events e)
{
if (_event1 == e )
{
host->CallAction();
}
if (_event2 == e)
{
target->CallSomeOtherAction();
}
}
So now cmd needs to be an instance variable of both EventManager and Target right? Now EventManager has host and target instance which can be passed to Command ctor.
But Target doesn't have access to host. So i cant create Command instance in Target class.
So i was wondering if i create the singleton in EventManager ctor. And then call GetInstance() in Target. I know its bad idea but with this huge design, iam not able to figure out. Thanks for your help.
I really do not understand your problem, but, just from the title, I can say this: Don't use a singleton. The fact that it requires arguments is a pretty good counter-indicator for the singleton pattern.
If you want to make sure that all commands are created with the same parameters, you can provide the client with a CommandFactory that creates instances of commands.
class CommandFactory {
public:
CommandFactory(std::string host, std::string target)
: m_host(host),
m_target(target)
{}
boost::shared_ptr<Command> createCommand() {
return boost::shared_ptr<Command>(new Command(m_host, m_target));
}
private:
std::string m_host;
std::string m_target;
};
Then you could also implement some kind of object pool to reuse objects.
There is absolutely no need to make Command a singleton. Just instantiate one as you need it with the proper parameters, pass it to the manager, use it and get rid of it. You probably want to pass it, so it is a good idea to use a shared_ptr.

What's a good safe way to initialise memory for types I don't yet know about?

I started thinking about this after receiving an answer for this question. This is a bit tricky to explain, but I'll do my best.
I'm building a small(ish) 2D game engine. There are certain requirements that I need to satisfy, since this engine has to "work" with existing code that others have written for a different engine. Some change to existing code is inevitable, but I want to minimise it.
Users of my engine need to define entities called "gadgets". These are basically structs containing shapes and other state variables. These "gadgets" fall into classes, e.g. they may decide to define an icon gadget or a button gadget - or whatever.
They will also define a message handler for that class of gadgets.
E.g.
typedef struct
{
shape shapelist[5];
int num_options;
}interface;
static void interface_message_handler( interface * myself, message * msg )
{
switch( msg->type )
{
case NEW_MSG:
{
interface_descriptor * desc = msg->desc;
// initialize myself with contents of this message.
...
}
break;
....
}
}
Users have already given me the corresponding message handler function and also the number of bytes in a interface object. And they can then ask the engine to create new instances of their gadgets via IDs e.g:
engine->CreateNewGadget( interface_gadget_class_ID, welcome_interface_ID );
where interface_gadget_class_ID is the ID for that class of gadgets and welcome_interface_ID is the instance ID. At some point during CreateNewGadget I need to a) allocate memory to hold a new gadget and then call the gadget class's message handler on it, with a NEW_MSG so that it can initialize itself.
The problem is, if all I'm doing is allocating memory - that memory is uninitialized (and that means all the struct members are uninitialized - so if interface contains a vector, for example, then I'm going to get some wierd results if the message handler does anything with it ).
To avoid wierd results caused by doing stuff to unintialized memory, I really need to call a constructor for that memory as well before passing it to the gadget's message handler function.
e.g in the case of interface:
pfunc(new (memory) interface);
But my question is, if I have no knowledge of the types that users are creating, how can I do that?
// We create a typedef that refers to a function pointer
// which is a function that returns an interface pointer
typedef interface * (*GadgetFactory)(void);
// we'll actually create these functions by using this template function
// Different version of this function will produce different classes.
template<typename T>
interface * create_object()
{
return new T;
}
// This function takes care of setting everything up.
template<typename T>
void RegisterGadgetType(int gadget_type_id)
{
// Get outselves a copy of a pointer to the function that will make the object
GadgetFactory factory = create_object<T>;
// store factory somewhere
}
interface * CreateGadget(int gadget_type_id)
{
// get factory
GadgetFactory factory;
// factory will give me the actual object type I need.
return (*factory)();
}
RegisterGadgetType<S>(2);
CreateGadget(2);
as i see it, you always know because interface_gadget_class_ID defines the type to create.
you create a base c++ class: (corresponds to class interface in your example). this base class contains all of data members which are used by every interface subclass (that is, every gadget).
the base class also declares all methods common to every gadget. example: each gadget is able to receive a call handleMessage. handleMessage is pure virtual, because this method is the subclasses' role to fulfill.
then you extend/subclass to support the stuff you have to do with each gadget's specialization. at this point, you add the members and methods specific to each gadget subclass.
CreateNewGadget serves as a factory for all your subclasses, where the arguments determine which class you will create.
from there, c++ will handle construction/destruction, allocation sizes, etc..
if you're allowing plugins with their own factories in your engine, then you'll need another level, where third parties register their custom types and inherit from your base(s).
here's a simple layout of the interfaces (in non-compiled pseudo code):
namespace MONGadgets {
class t_interface {
protected:
t_interface(/* ... */);
public:
virtual ~t_interface();
/* each subclass must override handleMessage */
virtual t_result handleMessage(const t_message& message) = 0;
};
namespace InterfaceSubclasses {
class t_gadget1 : public t_interface {
public:
t_gadget1(const welcome_interface_ID& welcome);
virtual ~t_gadget1();
virtual t_result handleMessage(const t_message& message) {
std::cout << "t_gadget1\n";
}
/* gadget1 has no specific instance variables or methods to declare */
};
class t_gadget2 : public t_interface {
public:
t_gadget2(const welcome_interface_ID& welcome);
virtual ~t_gadget2();
virtual t_result handleMessage(const t_message& message) {
std::cout << "t_gadget2\n";
}
private:
/* here is an example of a method specific to gadget2: */
void drawShape(const unsigned& idx);
private:
/* here is gadget2's unique data: */
shape shapelist[5];
int num_options;
};
namespace ClassID {
enum { Gadget1 = 1, Gadget2 = 2 };
}
}
/* replaced by virtual t_result t_interface::handleMessage(const t_message&)
- static void interface_message_handler( interface * myself, message * msg );
*/
class t_gadget_factory {
public:
t_interface* CreateNewGadget(const interface_gadget_class_ID& classID, const welcome_interface_ID& welcome) {
switch (classID) {
case InterfaceSubclasses::ClassID::Gadget1 :
return new InterfaceSubclasses::gadget1(welcome);
case InterfaceSubclasses::ClassID::Gadget2 :
return new InterfaceSubclasses::gadget2(welcome);
/* ... */
}
}
};
}
Example code (ignoring my other suggestion, about factories and virtual functions):
typedef struct
{
shape shapelist[5];
int num_options;
} interface;
static void interface_message_handler( void * myself, message * msg )
{
switch( msg->type )
{
case NEW_MSG:
{
interface *self = new (myself) interface;
interface_descriptor * desc = msg->desc;
// initialize myself with contents of this message.
...
}
break;
case OTHER_MSG:
{
interface *self = static_cast<interface*>(myself);
...
}
break;
....
}
}
Then your CreateNewGadget code does:
void *ptr = malloc(some_amount);
msg newmsg;
newmsg.type = NEW_MSG;
// other fields
some_message_handler(ptr, &msg);
// now we have an initialized object, that we can add to our tree or whatever.
The less horrible version is more like this:
struct gadgetinterface {
virtual ~gadgetinterface() {}
virtual void handle_message(msg *) = 0;
};
struct mygadget : gadgetinterface {
void handle_message(msg *m) {
// no need for NEW_MSG, just do other messages
}
};
gadgetinterface *mygadget_factory(some parameters) {
// use some parameters, either passed to constructor or afterwards
return new mygadget();
}
Then we register a pointer to mygadget_factory with the gadget manager, and CreateNewGadget does this:
gadgetinterface *some_factory(some parameters); // that's it!
Where some_factory is the function pointer that was registered, so in the case of this gadget type, it points to mygadget_factory.