switch

Started by
12 comments, last by Triglav 19 years, 8 months ago
in my previous project I solved this problem in the same way. the part of that project was also embedded Python interpreter, so the type-register code was written as "theme registration" in script. the type registration was also directly connected with initialization of various object modificators (because of simplicity of this example I removed several of them):

def RegisterThemeHall(interface):  theme = wrapper.Theme.Interface(interface)### TILES  # ...### STATICS  # ...### DYNAMICS###                type        image_id                 move_type     speed range power hp  theme.DynamicObj(DT.Hero,    IDI.HERO.TYPE_01[0],     MoveType.WALK, 3.5,    0,   2, 200)  theme.DynamicObj(DT.Hero,    IDI.HERO.TYPE_02[0],     MoveType.WALK, 3.5,    0,   2, 200)  theme.DynamicObj(DT.Monster, IDI.MONSTER.GREEN[0],    MoveType.WALK, 3.0,  200,   2,  75)  theme.DynamicObj(DT.Monster, IDI.MONSTER.MUCILAGE[0], MoveType.WALK, 1.5,  130,  10,  80)  theme.DynamicObj(DT.Monster, IDI.MONSTER.RADIO[0],    MoveType.WALK, 1.0,  150,  10, 120)  theme.DynamicObj(DT.Monster, IDI.MONSTER.MAGE[0],     MoveType.WALK, 1.0,  200,  15, 150)  theme.DynamicObj(DT.Missile, IDI.MISSILE.PULSE[0],    MoveType.FLY,  7.0,  110,  30,   0)  theme.DynamicObj(DT.Missile, IDI.MISSILE.MUCILAGE[0], MoveType.FLY,  5.0,  140,  20,   0)  theme.DynamicObj(DT.Missile, IDI.MISSILE.MAGIC[0],    MoveType.FLY,  8.0,  400,  45,   0)#RegisterThemeHall()def RegisterThemeStore(interface):  # ...#RegisterThemeStore()def RegisterThemeCellar(interface):  # ...#RegisterThemeCellar()RegisterFunction = {}RegisterFunction[0x00] = RegisterThemeCellarRegisterFunction[0x01] = RegisterThemeStoreRegisterFunction[0x02] = RegisterThemeHalldef Register(theme_pointer, theme_id):    """ Loads current type data.        'data_pointer' is a pointer        to data interface in C/C++ code.    """    try:        RegisterFunction[theme_id](theme_pointer)    except:        raise#Register()


I know, ugly, but those times it worked nice for me and the deadline was approaching (I wrote the glue code by hand). now the problem is that the object definition is opened and limited by the 'theme.DynamicObj()' function. using the technique mentioned above, those ugly lines will be changed to something as follows (because I'm lazy that ugly stuff with function array is still there):

def RegisterThemeHall(interface):  theme = wrapper.Theme.Interface(interface)  # ...### DYNAMICS  theme.DynamicObj(DT.Hero.Type01)  theme.DynamicObj(DT.Hero.Type02)  theme.DynamicObj(DT.Monster.Green)  theme.DynamicObj(DT.Monster.Mucilage)  theme.DynamicObj(DT.Monster.Radio)  theme.DynamicObj(DT.Monster.Mage)  theme.DynamicObj(DT.Missile.Pulse)  theme.DynamicObj(DT.Missile.Mucilage)  theme.DynamicObj(DT.Missile.Magic)#RegisterThemeHall()


the only reason that I founded this thread is that I was wondering whether it's necessary to register newly added objects. whether there is no technique to bypass the cursed land.

suppose that we are using a scripting language for defining our new objects (than it's opened for extern contributors and fans[smile]). today I'm using Lua, so here is something:

-- Registers all objects defined in "obj_dir" directoryfunction registerObjectDir(_obj_dir)  local directoryList = io.dircontents(_obj_dir)  for objectFile in directoryList do    registerObject(objectFile)  endend


you have an idea. but how to write something as about in C++ that only one thing to add new object is to link it with new object compiled in .o file?
Triglav - Member of TAJGA Team
Advertisement
Quote:Original post by Triglav
you have an idea. but how to write something as about in C++ that only one thing to add new object is to link it with new object compiled in .o file?


My code above gives an example of how a user would "register" the object without having to store the registration code in a central place. Basically I used this object (para-phrasing):

template<typename TBuilder>class TBuilderRegistrar {public:  TBuilderRegistrar() {    ObjectManager::Instance()->RegisterBuilder(TBuilder::ID, new TBuilder());  }};


Instantiating an object of the above type will automatically register the builder with the object manager. You just have to include the following line in your module (not your header file):

TBuilderRegistrar<MyNewObject4> registerMyNewObject4;// describe all MyNewObject4 members here:MyNewObject4::MyNewObject4(...) {}....


Thus, someone who wants to add a new object type has to:

1) create a header file that describes their new object (inheriting from your base object)
2) create a simple builder class that matches the builder interface (i.e. inherits from the builder base class)
3) in the source module file (.cpp) instantiate a builder registrar object
4) describe their new object methods

You can macro-ize #3 if you want into something equivalant of:

REGISTER_OBJECT(MyNewObject4);

Regards,
Jeff
Quote:Original post by Triglav
hi, I read some nice stuffs about virtual copy-constructors in Scott Meyers book "More Effective C++". now I'm wondering whether there is any technique to eliminate the switch statement (or function pointers) in following example:

*** Source Snippet Removed ***

I'm finding some nice and robust way. there should be no changes in code, when new object types needs to be added.


Haven't read the whole thread but looking at your code i can't see the virtual constructor idiom being used in your code, you can read more about it here this is how you would implement virtual constructors and how you could use this to eliminate that switch statement:

#include <string>#include <iostream>template< typename T >struct cloneable {   virtual T* clone() const = 0;   virtual ~cloneable() = 0;};template< typename T >cloneable<T>::~cloneable() {}template< typename T >struct constructable {   virtual T* create() const = 0;   virtual ~constructable() = 0;};template< typename T >constructable<T>::~constructable() {}struct object_interface : constructable<object_interface>, cloneable<object_interface> {  //la-la-la   virtual ~object_interface() = 0;};object_interface::~object_interface() {}//concreate type must implement clone & create methodsclass object_type0 : object_interface {   int a;public:   //default constructor   object_type0(int b = 0)   : object_interface(), a(b) {}   object_type0(const object_type0& o)   : object_interface(o), a(o.a) {}   object_type0& operator=(const object_type0& o) {       object_interface::operator=(o);       if(this != &o)          a = o.a;       return *this;   }   object_interface* create() const {      return new object_type0();   }   object_interface* clone() const {      return new object_type0(*this);   }};//concreate type must implement clone & create methodsclass object_type1 : object_interface {   std::string _s;public:   //default constructor   object_type1(const std::string& s = std::string())   : object_interface(), _s(s) {}   object_type1(const object_type1& o)   : object_interface(o), _s(o._s) {}   object_type1& operator=(const object_type1& o) {       object_interface::operator=(o);       if(this != &o)          _s = o._s;       return *this;   }   object_interface* create() const {      return new object_type1();   }   object_interface* clone() const {      return new object_type1(*this);   }};//example of using virtual constructor idiomint main() {   object_type0 b;   object_interface* i = b.clone();   object_interface* i2 = i->clone();     object_interface* i3 = i2->clone();   delete i;   delete i2;   delete i3;   return 0;}


[Edited by - snk_kid on August 9, 2004 3:42:16 AM]
Quote:Original post by rypyr
My code above gives an example of how a user would "register" the object without having to store the registration code in a central place.


ah, thank you, I was blind
Triglav - Member of TAJGA Team

This topic is closed to new replies.

Advertisement