Choosing a class using a variable without if-else

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • David Sanders

    Choosing a class using a variable without if-else

    Hi,

    As part of a simulation program, I have several different model
    classes, ModelAA, ModelBB, etc., which are all derived from the class
    BasicModel by inheritance.
    >From a command-line parameter, I need to choose the correct type of
    model to use, for example if the parameter model_name is "aa", then
    choose ModelAA.

    Currently I do this as follows:

    BasicModel* model;

    if (model_name == "aa") {
    model = new ModelAA(a,b,c);
    }

    else if (model_name == "bb") {
    model = new ModelBB(a,b,c);
    }

    etc., through all the (many) models.
    Each model constructor takes the same parameters, if this is of any
    help.

    Once this is done, only virtual functions in BasicModel are called.
    (But the implementation of these can be very different in the different
    kinds of model.)

    It is clear to me that there must be a better way of initiating the
    models, which is easier to update when a new model is added, e.g.
    involving some kind of array or map, mapping the model_name string to
    the class name, but I can't work out the syntax (I am somewhat of a
    newbie).

    I have looked hard at the FAQ, and I cannot see anything that is
    relevant (but please correct me if I'm wrong). Any suggestions or
    pointers would be greatly appreciated.

    Thanks and best wishes,
    David.

  • kwikius

    #2
    Re: Choosing a class using a variable without if-else


    David Sanders wrote:
    It is clear to me that there must be a better way of initiating the
    models, which is easier to update when a new model is added, e.g.
    involving some kind of array or map, mapping the model_name string to
    the class name, but I can't work out the syntax (I am somewhat of a
    newbie).
    #include <map>
    #include <string>
    #include <iostream>

    struct BasicModel{
    virtual ~BasicModel(){}
    // function to identify which it is
    virtual const char * sig() const = 0;
    };

    struct ModelAA : BasicModel{
    ModelAA(int a, int b, int c){}
    const char * sig() const {return "model aa";}
    };

    struct ModelBB : BasicModel{
    ModelBB(int a, int b, int c){}
    const char * sig() const {return "model bb";}
    };

    BasicModel* make_model_aa(i nt a, int b, int c)
    {
    return new ModelAA(a,b,c);
    }

    BasicModel* make_model_bb(i nt a, int b, int c)
    {
    return new ModelBB(a,b,c);
    }

    typedef std::map<
    std::string,
    BasicModel* (*)( int,int,int)
    model_map_type;
    int main()
    {
    model_map_type model_maker;
    model_maker["aa"]= make_model_aa;
    model_maker["bb"]= make_model_bb;

    BasicModel * pmaa = model_maker["aa"](1,2,3);
    std::cout << pmaa->sig() <<'\n';

    BasicModel * pmbb = model_maker["bb"](1,2,3);
    std::cout << pmbb->sig() <<'\n';
    }

    Comment

    • Greg

      #3
      Re: Choosing a class using a variable without if-else

      David Sanders wrote:
      As part of a simulation program, I have several different model
      classes, ModelAA, ModelBB, etc., which are all derived from the class
      BasicModel by inheritance.
      >
      From a command-line parameter, I need to choose the correct type of
      model to use, for example if the parameter model_name is "aa", then
      choose ModelAA.
      >
      Currently I do this as follows:
      >
      BasicModel* model;
      >
      if (model_name == "aa") {
      model = new ModelAA(a,b,c);
      }
      >
      else if (model_name == "bb") {
      model = new ModelBB(a,b,c);
      }
      >
      etc., through all the (many) models.
      Each model constructor takes the same parameters, if this is of any
      help.
      I would suggest implementing a "registrati on" model, in which each
      BasicModel subclass has to register its name and its static creation
      routine in a central map. The routine that creates BasicModel subclass
      objects by name would consult this central map in order to match the
      class name with the appropriate creation routine that had been
      registered. If a routine is found, then it is invoked to create an
      object of the requested type.

      To enforce registration, each BasicModel subclass would inherit from a
      "ClassMap" template with the template's type parameter being the
      BasicModel subclass itself. Each BasicModel subclass would also have to
      implement two static routines (or it would not compile): a GetName()
      routine (returning the name used to create an object of that class) and
      a static Create() routine that allocates an object of the matching
      class.

      Here is a basic implementation of the preceding ideas in case you would
      like to experiment with any of them:

      #include <iostream>
      #include <map>
      #include <string>

      using std::map;
      using std::string;

      class BasicModel;

      typedef map<string, BasicModel* (*)()ClassNameM ap;

      struct ClassMapBase
      {
      static ClassNameMap sClassMap;
      };

      template <class T>
      struct ClassMap : public ClassMapBase
      {
      ClassMap(const string& name = std::string("") )
      {
      if (name.length())
      {
      std::cout << "Registerin g: " << T::GetName() << "\n";

      sInstance.sClas sMap[ T::GetName()] = T::Create;
      }
      }
      static ClassMap sInstance;
      };

      class BasicModel
      {
      public:
      BasicModel() {}

      static
      BasicModel* CreateByName( const string& name)
      {
      ClassNameMap::i terator iter;

      iter = ClassMapBase::s ClassMap.find( name );

      if (iter != ClassMapBase::s ClassMap.end())
      {
      return (*iter).second( );
      }
      return NULL;
      }
      };

      // ModelAA inherits from ClassMap thereby registering itself

      class ModelAA : public BasicModel, ClassMap<ModelA A>
      {
      public:
      ModelAA() : BasicModel() {}

      // required GetName() routine

      static string GetName()
      {
      return "aa";
      }

      // required Create() routine

      static BasicModel * Create()
      {
      return new ModelAA;
      }
      };

      // some class static variables

      ClassNameMap ClassMapBase::s ClassMap;

      // the self-registering static variable

      template <class T>
      ClassMap<TClass Map<T>::sInstan ce( T::GetName() );

      int main()
      {
      BasicModel * a = BasicModel::Cre ateByName("aa") ;

      // a is a ModelAA *
      }

      Program Output:

      Registering: aa

      Greg

      Comment

      • andrewmcdonagh

        #4
        Re: Choosing a class using a variable without if-else



        On Dec 23, 9:51 am, "Greg" <gre...@pacbell .netwrote:
        David Sanders wrote:
        As part of a simulation program, I have several different model
        classes, ModelAA, ModelBB, etc., which are all derived from the class
        BasicModel by inheritance.
        >
        From a command-line parameter, I need to choose the correct type of
        model to use, for example if the parameter model_name is "aa", then
        choose ModelAA.
        >
        Currently I do this as follows:
        >
        BasicModel* model;
        >
        if (model_name == "aa") {
        model = new ModelAA(a,b,c);
        }
        >
        else if (model_name == "bb") {
        model = new ModelBB(a,b,c);
        }
        >
        etc., through all the (many) models.
        Each model constructor takes the same parameters, if this is of any
        help.I would suggest implementing a "registrati on" model, in which each
        BasicModel subclass has to register its name and its static creation
        routine in a central map. The routine that creates BasicModel subclass
        objects by name would consult this central map in order to match the
        class name with the appropriate creation routine that had been
        registered. If a routine is found, then it is invoked to create an
        object of the requested type.
        >
        To enforce registration, each BasicModel subclass would inherit from a
        "ClassMap" template with the template's type parameter being the
        BasicModel subclass itself. Each BasicModel subclass would also have to
        implement two static routines (or it would not compile): a GetName()
        routine (returning the name used to create an object of that class) and
        a static Create() routine that allocates an object of the matching
        class.
        >
        Here is a basic implementation of the preceding ideas in case you would
        like to experiment with any of them:
        >
        #include <iostream>
        #include <map>
        #include <string>
        >
        using std::map;
        using std::string;
        >
        class BasicModel;
        >
        typedef map<string, BasicModel* (*)()ClassNameM ap;
        >
        struct ClassMapBase
        {
        static ClassNameMap sClassMap;
        };
        >
        template <class T>
        struct ClassMap : public ClassMapBase
        {
        ClassMap(const string& name = std::string("") )
        {
        if (name.length())
        {
        std::cout << "Registerin g: " << T::GetName() << "\n";
        >
        sInstance.sClas sMap[ T::GetName()] = T::Create;
        }
        }
        static ClassMap sInstance;
        };
        >
        class BasicModel
        {
        public:
        BasicModel() {}
        >
        static
        BasicModel* CreateByName( const string& name)
        {
        ClassNameMap::i terator iter;
        >
        iter = ClassMapBase::s ClassMap.find( name );
        >
        if (iter != ClassMapBase::s ClassMap.end())
        {
        return (*iter).second( );
        }
        return NULL;
        }
        };
        >
        // ModelAA inherits from ClassMap thereby registering itself
        >
        class ModelAA : public BasicModel, ClassMap<ModelA A>
        {
        public:
        ModelAA() : BasicModel() {}
        >
        // required GetName() routine
        >
        static string GetName()
        {
        return "aa";
        }
        >
        // required Create() routine
        >
        static BasicModel * Create()
        {
        return new ModelAA;
        }
        };
        >
        // some class static variables
        >
        ClassNameMap ClassMapBase::s ClassMap;
        >
        // the self-registering static variable
        >
        template <class T>
        ClassMap<TClass Map<T>::sInstan ce( T::GetName() );
        >
        int main()
        {
        BasicModel * a = BasicModel::Cre ateByName("aa") ;
        >
        // a is a ModelAA *
        }
        >
        Program Output:
        >
        Registering: aa
        >
        Greg- Hide quoted text -- Show quoted text -
        Nice design, my only input would be that its not usually a good idea to
        have base classes know about derived classes - in your case this
        knowledge is purely by id and pointer to factory method, instead of a
        direct knowledge association.

        To finish the design, I would move the CreateByName() method to a
        ModelFactory class. This way we keep the ideal of base classes not
        knowing about derived classes and more importantly, we have a design
        the is compliant with the Single Responsability Principle.

        Comment

        • andrewmcdonagh

          #5
          Re: Choosing a class using a variable without if-else



          On Dec 23, 7:52 am, "kwikius" <a...@servocomm .freeserve.co.u kwrote:
          David Sanders wrote:
          It is clear to me that there must be a better way of initiating the
          models, which is easier to update when a new model is added, e.g.
          involving some kind of array or map, mapping the model_name string to
          the class name, but I can't work out the syntax (I am somewhat of a
          newbie).#includ e <map>
          #include <string>
          #include <iostream>
          >
          struct BasicModel{
          virtual ~BasicModel(){}
          // function to identify which it is
          virtual const char * sig() const = 0;
          >
          };struct ModelAA : BasicModel{
          ModelAA(int a, int b, int c){}
          const char * sig() const {return "model aa";}
          >
          };struct ModelBB : BasicModel{
          ModelBB(int a, int b, int c){}
          const char * sig() const {return "model bb";}
          >
          };BasicModel* make_model_aa(i nt a, int b, int c)
          {
          return new ModelAA(a,b,c);
          >
          }BasicModel* make_model_bb(i nt a, int b, int c)
          {
          return new ModelBB(a,b,c);
          >
          }typedef std::map<
          std::string,
          BasicModel* (*)( int,int,int)
          >
          model_map_type; int main()
          {
          model_map_type model_maker;
          model_maker["aa"]= make_model_aa;
          model_maker["bb"]= make_model_bb;
          >
          BasicModel * pmaa = model_maker["aa"](1,2,3);
          std::cout << pmaa->sig() <<'\n';
          >
          BasicModel * pmbb = model_maker["bb"](1,2,3);
          std::cout << pmbb->sig() <<'\n';
          >
          >
          >
          The idea is right, but there is currently an implementation problem of
          the base class knowing about its derived classes.

          This design currently violates the OpenClosed Principle. See my reply
          to Greg's message for a slight modification which would solve this.

          Andrew

          Comment

          • kwikius

            #6
            Re: Choosing a class using a variable without if-else


            andrewmcdonagh wrote:
            On Dec 23, 7:52 am, "kwikius" <a...@servocomm .freeserve.co.u kwrote:
            David Sanders wrote:
            It is clear to me that there must be a better way of initiating the
            models, which is easier to update when a new model is added, e.g.
            involving some kind of array or map, mapping the model_name string to
            the class name, but I can't work out the syntax (I am somewhat of a
            newbie).#includ e <map>
            #include <string>
            #include <iostream>

            struct BasicModel{
            virtual ~BasicModel(){}
            // function to identify which it is
            virtual const char * sig() const = 0;

            };struct ModelAA : BasicModel{
            ModelAA(int a, int b, int c){}
            const char * sig() const {return "model aa";}

            };struct ModelBB : BasicModel{
            ModelBB(int a, int b, int c){}
            const char * sig() const {return "model bb";}

            };BasicModel* make_model_aa(i nt a, int b, int c)
            {
            return new ModelAA(a,b,c);

            }BasicModel* make_model_bb(i nt a, int b, int c)
            {
            return new ModelBB(a,b,c);

            }typedef std::map<
            std::string,
            BasicModel* (*)( int,int,int)
            model_map_type; int main()
            {
            model_map_type model_maker;
            model_maker["aa"]= make_model_aa;
            model_maker["bb"]= make_model_bb;

            BasicModel * pmaa = model_maker["aa"](1,2,3);
            std::cout << pmaa->sig() <<'\n';

            BasicModel * pmbb = model_maker["bb"](1,2,3);
            std::cout << pmbb->sig() <<'\n';

            >
            The idea is right, but there is currently an implementation problem of
            the base class knowing about its derived classes.
            You lost me I'm afraid. The design is simple and conforms to the spec
            of the O.P.
            This design currently violates the OpenClosed Principle. See my reply
            to Greg's message for a slight modification which would solve this.
            I think you need to provide more details as to how it violates the
            OpenClosed principle.

            regards
            Andy Little

            Comment

            • andrewmcdonagh

              #7
              Re: Choosing a class using a variable without if-else



              On Dec 23, 12:54 pm, "kwikius" <a...@servocomm .freeserve.co.u kwrote:
              andrewmcdonagh wrote:
              On Dec 23, 7:52 am, "kwikius" <a...@servocomm .freeserve.co.u kwrote:
              David Sanders wrote:
              It is clear to me that there must be a better way of initiating the
              models, which is easier to update when a new model is added, e.g.
              involving some kind of array or map, mapping the model_name string to
              the class name, but I can't work out the syntax (I am somewhat of a
              newbie).#includ e <map>
              #include <string>
              #include <iostream>
              >
              struct BasicModel{
              virtual ~BasicModel(){}
              // function to identify which it is
              virtual const char * sig() const = 0;
              >
              };struct ModelAA : BasicModel{
              ModelAA(int a, int b, int c){}
              const char * sig() const {return "model aa";}
              >
              };struct ModelBB : BasicModel{
              ModelBB(int a, int b, int c){}
              const char * sig() const {return "model bb";}
              >
              };BasicModel* make_model_aa(i nt a, int b, int c)
              {
              return new ModelAA(a,b,c);
              >
              }BasicModel* make_model_bb(i nt a, int b, int c)
              {
              return new ModelBB(a,b,c);
              >
              }typedef std::map<
              std::string,
              BasicModel* (*)( int,int,int)
              >
              model_map_type; int main()
              {
              model_map_type model_maker;
              model_maker["aa"]= make_model_aa;
              model_maker["bb"]= make_model_bb;
              >
              BasicModel * pmaa = model_maker["aa"](1,2,3);
              std::cout << pmaa->sig() <<'\n';
              >
              BasicModel * pmbb = model_maker["bb"](1,2,3);
              std::cout << pmbb->sig() <<'\n';
              >
              The idea is right, but there is currently an implementation problem of
              the base class knowing about its derived classes.You lost me I'm afraid. The design is simple and conforms to the spec
              of the O.P.
              Sure it does, I'm just commenting on that simple is not always correct
              and other simple approaches can help over come these.
              >
              This design currently violates the OpenClosed Principle. See my reply
              to Greg's message for a slight modification which would solve this.I think you need to provide more details as to how it violates the
              OpenClosed principle.
              >
              regards
              If we want to add a new derived class zz, then we need to
              1) Create our new claa ModelZZ
              2) modify BasicModel to include knowledge of the new class.
              3) Recompile all effected code because BasicModel's interface has
              changed

              This means BasicModel is not conformant, its not 'Open to extension but
              closed to modification'

              Take a look at
              http://dforge.cse.ucsc.edu/docman/vi...OpenClosed.pdf for more
              info....

              So, what I was suggesting to Greg, was to move the construction logic
              to its own class, making BasicModel changes unneeded.

              HTH

              Andrew

              Comment

              • David Sanders

                #8
                Re: Choosing a class using a variable without if-else


                kwikius wrote:
                andrewmcdonagh wrote:
                On Dec 23, 7:52 am, "kwikius" <a...@servocomm .freeserve.co.u kwrote:
                David Sanders wrote:
                It is clear to me that there must be a better way of initiating the
                models, which is easier to update when a new model is added, e.g.
                involving some kind of array or map, mapping the model_name string to
                the class name, but I can't work out the syntax (I am somewhat of a
                newbie).#includ e <map>
                #include <string>
                #include <iostream>
                >
                struct BasicModel{
                virtual ~BasicModel(){}
                // function to identify which it is
                virtual const char * sig() const = 0;
                >
                };struct ModelAA : BasicModel{
                ModelAA(int a, int b, int c){}
                const char * sig() const {return "model aa";}
                >
                };struct ModelBB : BasicModel{
                ModelBB(int a, int b, int c){}
                const char * sig() const {return "model bb";}
                >
                };BasicModel* make_model_aa(i nt a, int b, int c)
                {
                return new ModelAA(a,b,c);
                >
                }BasicModel* make_model_bb(i nt a, int b, int c)
                {
                return new ModelBB(a,b,c);
                >
                }typedef std::map<
                std::string,
                BasicModel* (*)( int,int,int)
                >
                model_map_type; int main()
                {
                model_map_type model_maker;
                model_maker["aa"]= make_model_aa;
                model_maker["bb"]= make_model_bb;
                >
                BasicModel * pmaa = model_maker["aa"](1,2,3);
                std::cout << pmaa->sig() <<'\n';
                >
                BasicModel * pmbb = model_maker["bb"](1,2,3);
                std::cout << pmbb->sig() <<'\n';
                >
                >
                >
                The idea is right, but there is currently an implementation problem of
                the base class knowing about its derived classes.
                >
                You lost me I'm afraid. The design is simple and conforms to the spec
                of the O.P.
                >
                This design currently violates the OpenClosed Principle. See my reply
                to Greg's message for a slight modification which would solve this.
                >
                I think you need to provide more details as to how it violates the
                OpenClosed principle.
                Many thanks to all for the suggestions. I have some work to do to
                understand the answers, but at least I now understand the reason for
                design patterns.

                Thanks and best wishes,
                David.

                Comment

                • Daniel T.

                  #9
                  Re: Choosing a class using a variable without if-else

                  In article <1166857387.788 421.318030@48g2 000cwx.googlegr oups.com>,
                  "David Sanders" <dpsanders@gmai l.comwrote:
                  Hi,
                  >
                  As part of a simulation program, I have several different model
                  classes, ModelAA, ModelBB, etc., which are all derived from the class
                  BasicModel by inheritance.
                  >
                  From a command-line parameter, I need to choose the correct type of
                  model to use, for example if the parameter model_name is "aa", then
                  choose ModelAA.
                  >
                  Currently I do this as follows:
                  >
                  BasicModel* model;
                  >
                  if (model_name == "aa") {
                  model = new ModelAA(a,b,c);
                  }
                  >
                  else if (model_name == "bb") {
                  model = new ModelBB(a,b,c);
                  }
                  >
                  etc., through all the (many) models.
                  Each model constructor takes the same parameters, if this is of any
                  help.
                  >
                  Once this is done, only virtual functions in BasicModel are called.
                  (But the implementation of these can be very different in the different
                  kinds of model.)
                  >
                  It is clear to me that there must be a better way of initiating the
                  models, which is easier to update when a new model is added, e.g.
                  involving some kind of array or map, mapping the model_name string to
                  the class name, but I can't work out the syntax (I am somewhat of a
                  newbie).
                  >
                  I have looked hard at the FAQ, and I cannot see anything that is
                  relevant (but please correct me if I'm wrong). Any suggestions or
                  pointers would be greatly appreciated.
                  I think it is important to note that the "extra work" you are trying to
                  avoid is adding 2 lines in your main every time you make a new
                  sub-class. That's not much...

                  In order to save you extra work in this case, the solution must allow
                  you to add a new class to main with only one line of extra code, and the
                  number of classes must be great enough to justify the amount of code
                  required to allow that one line to work.

                  The best solution I can think of would allow you to add a new class by
                  doing this:

                  --- AA.cpp
                  #include "AA.h"

                  ModelCreator<AA creatorAA( "aa" );


                  --- AA.h
                  #include "Model.h"

                  class Aa : public Model
                  { };


                  Thus only one line adds a new model sub-type to main and that one line
                  can be put in the cpp file of the class. In order for this to work, you
                  need the following:

                  --- Model.h
                  #include <map>
                  #include <string>

                  class Model
                  {
                  public:
                  virtual ~Model() { }
                  };

                  // support for model creation
                  class ModelCreatorT {
                  public:
                  virtual Model* create() const = 0;
                  };

                  std::map< std::string, ModelCreatorT* >& modelMap();

                  template < typename T >
                  class ModelCreator : public ModelCreatorT
                  {
                  public:
                  ModelCreator( const char* name ) {
                  modelMap()[name] = this;
                  }

                  Model* create() const {
                  return new T;
                  }
                  };


                  --- Model.cpp
                  #include "Model.h"

                  using namespace std;

                  map<string, ModelCreatorT*> & modelMap() {
                  static map<string, ModelCreatorT*m odels;
                  return models;
                  }


                  --- main.cpp
                  #include "Model.h"

                  int main( int argc, char* argv[] )
                  {
                  if ( argc 1 )
                  {
                  Model* m = modelMap()[argv[1]]->create();
                  // use m
                  delete m;
                  }
                  }


                  Now you have to judge if the number of sub-classes of Model is enough to
                  justify the extra work needed to save you extra work. :-)

                  Comment

                  • kwikius

                    #10
                    Re: Choosing a class using a variable without if-else


                    andrewmcdonagh wrote:
                    If we want to add a new derived class zz, then we need to
                    1) Create our new claa ModelZZ
                    2) modify BasicModel to include knowledge of the new class.
                    3) Recompile all effected code because BasicModel's interface has
                    changed.
                    No offence but that you are talking complete nonsense.

                    Here is my code copied from the other post. I've marked the sections
                    added to create some modelZZ. There has been no mods to the ABC
                    required to run this

                    regards
                    Andy Little

                    ----------------------------------
                    #include <map>
                    #include <string>
                    #include <iostream>

                    struct BasicModel{
                    virtual ~BasicModel(){}
                    // function to identify which it is
                    virtual const char * sig() const = 0;
                    };


                    struct ModelAA : BasicModel{
                    ModelAA(int a, int b, int c){}
                    const char * sig() const {return "model aa";}
                    };


                    struct ModelBB : BasicModel{
                    ModelBB(int a, int b, int c){}
                    const char * sig() const {return "model bb";}
                    };


                    BasicModel* make_model_aa(i nt a, int b, int c)
                    {
                    return new ModelAA(a,b,c);
                    }


                    BasicModel* make_model_bb(i nt a, int b, int c)
                    {
                    return new ModelBB(a,b,c);
                    }


                    typedef std::map<
                    std::string,
                    BasicModel* (*)( int,int,int)
                    model_map_type;

                    //////////////////// new code //////////

                    struct ModelZZ : BasicModel{
                    ModelZZ(int a, int b, int c){}
                    const char * sig() const {return "model zz";}
                    };


                    BasicModel* make_model_zz(i nt a, int b, int c)
                    {
                    return new ModelZZ(a,b,c);
                    }

                    ////////////// end new code//////////
                    int main()
                    {
                    model_map_type model_maker;
                    model_maker["aa"]= make_model_aa;
                    model_maker["bb"]= make_model_bb;

                    BasicModel * pmaa = model_maker["aa"](1,2,3);
                    std::cout << pmaa->sig() <<'\n';

                    BasicModel * pmbb = model_maker["bb"](1,2,3);
                    std::cout << pmbb->sig() <<'\n';

                    ////////new code //////////////////

                    model_maker["zz"]= make_model_zz;

                    BasicModel * pmzz = model_maker["zz"](1,2,3);
                    std::cout << pmzz->sig() <<'\n';

                    //////// end new code ////////////////////

                    }

                    Comment

                    • kwikius

                      #11
                      Re: Choosing a class using a variable without if-else

                      andrewmcdonagh wrote
                      kwikius wrote:
                      andrewmcdonagh wrote:
                      You lost me I'm afraid. The design is simple and conforms to the spec
                      of the O.P.
                      >
                      Sure it does, I'm just commenting on that simple is not always correct
                      and other simple approaches can help over come these.
                      You've still not shown me any proof that my example is incorrect.
                      You have implied that it is incorrect several times however. Maybe now
                      you should either prove your point or apologise for making incorrect
                      statements.
                      This design currently violates the OpenClosed Principle. See my reply
                      to Greg's message for a slight modification which would solve this.I think you need to provide more details as to how it violates the
                      OpenClosed principle.

                      regards
                      >
                      If we want to add a new derived class zz, then we need to
                      1) Create our new claa ModelZZ
                      2) modify BasicModel to include knowledge of the new class.
                      3) Recompile all effected code because BasicModel's interface has
                      changed
                      >
                      This means BasicModel is not conformant, its not 'Open to extension but
                      closed to modification'
                      That 2nd statement is simply incorrect AFAICS. You need to show me an
                      example to prove your point.

                      According to that doc an ABC is a perfectly valid example of
                      conformance to the so-called open closed principle....
                      So, what I was suggesting to Greg, was to move the construction logic
                      to its own class, making BasicModel changes unneeded.
                      >
                      HTH
                      No I don't think you are helping very much FWIW. Examples please ?

                      regards
                      Andy Little

                      Comment

                      • David Sanders

                        #12
                        Re: Choosing a class using a variable without if-else


                        Daniel T. wrote:
                        In article <1166857387.788 421.318030@48g2 000cwx.googlegr oups.com>,
                        "David Sanders" <dpsanders@gmai l.comwrote:
                        >
                        Hi,

                        As part of a simulation program, I have several different model
                        classes, ModelAA, ModelBB, etc., which are all derived from the class
                        BasicModel by inheritance.
                        >From a command-line parameter, I need to choose the correct type of
                        model to use, for example if the parameter model_name is "aa", then
                        choose ModelAA.

                        Currently I do this as follows:

                        BasicModel* model;

                        if (model_name == "aa") {
                        model = new ModelAA(a,b,c);
                        }

                        else if (model_name == "bb") {
                        model = new ModelBB(a,b,c);
                        }

                        etc., through all the (many) models.
                        Each model constructor takes the same parameters, if this is of any
                        help.

                        Once this is done, only virtual functions in BasicModel are called.
                        (But the implementation of these can be very different in the different
                        kinds of model.)

                        It is clear to me that there must be a better way of initiating the
                        models, which is easier to update when a new model is added, e.g.
                        involving some kind of array or map, mapping the model_name string to
                        the class name, but I can't work out the syntax (I am somewhat of a
                        newbie).

                        I have looked hard at the FAQ, and I cannot see anything that is
                        relevant (but please correct me if I'm wrong). Any suggestions or
                        pointers would be greatly appreciated.
                        >
                        I think it is important to note that the "extra work" you are trying to
                        avoid is adding 2 lines in your main every time you make a new
                        sub-class. That's not much...
                        >
                        In order to save you extra work in this case, the solution must allow
                        you to add a new class to main with only one line of extra code, and the
                        number of classes must be great enough to justify the amount of code
                        required to allow that one line to work.
                        >
                        The best solution I can think of would allow you to add a new class by
                        doing this:
                        >
                        --- AA.cpp
                        #include "AA.h"
                        >
                        ModelCreator<AA creatorAA( "aa" );
                        >
                        >
                        --- AA.h
                        #include "Model.h"
                        >
                        class Aa : public Model
                        { };
                        >
                        >
                        Thus only one line adds a new model sub-type to main and that one line
                        can be put in the cpp file of the class. In order for this to work, you
                        need the following:
                        >
                        --- Model.h
                        #include <map>
                        #include <string>
                        >
                        class Model
                        {
                        public:
                        virtual ~Model() { }
                        };
                        >
                        // support for model creation
                        class ModelCreatorT {
                        public:
                        virtual Model* create() const = 0;
                        };
                        >
                        std::map< std::string, ModelCreatorT* >& modelMap();
                        >
                        template < typename T >
                        class ModelCreator : public ModelCreatorT
                        {
                        public:
                        ModelCreator( const char* name ) {
                        modelMap()[name] = this;
                        }
                        >
                        Model* create() const {
                        return new T;
                        }
                        };
                        >
                        >
                        --- Model.cpp
                        #include "Model.h"
                        >
                        using namespace std;
                        >
                        map<string, ModelCreatorT*> & modelMap() {
                        static map<string, ModelCreatorT*m odels;
                        return models;
                        }
                        >
                        >
                        --- main.cpp
                        #include "Model.h"
                        >
                        int main( int argc, char* argv[] )
                        {
                        if ( argc 1 )
                        {
                        Model* m = modelMap()[argv[1]]->create();
                        // use m
                        delete m;
                        }
                        }
                        >
                        >
                        Now you have to judge if the number of sub-classes of Model is enough to
                        justify the extra work needed to save you extra work. :-)
                        Hi,
                        Thanks again to everybody who offered suggestions.
                        Daniel T.'s comes closest to what I was imagining, although I'm not
                        surprised I didn't manage it myself -- any of the solutions seem to be
                        rather complicated and non-intuitive.

                        I agree that it's not clear that the work saved is worth the extra
                        work, but I've certainly learnt a lot of nice C++ in the meantime! :-)
                        Where should I be looking to learn how to write code like this?
                        (If that's not a silly question.) I am interested in scientific
                        programming applications, where the same algorithm is applied to
                        disparate models, and I'm thus interested in learning how to increase
                        the abstraction level of my code (without sacrificing speed, of
                        course!)

                        Thanks and best wishes,
                        David.

                        Comment

                        • Daniel T.

                          #13
                          Re: Choosing a class using a variable without if-else

                          "David Sanders" <dpsanders@gmai l.comwrote:
                          Daniel T. wrote:
                          >
                          I think it is important to note that the "extra work" you are
                          trying to avoid is adding 2 lines in your main every time you make
                          a new sub-class. That's not much...

                          In order to save you extra work in this case, the solution must
                          allow you to add a new class to main with only one line of extra
                          code, and the number of classes must be great enough to justify
                          the amount of code required to allow that one line to work.
                          >
                          Thanks again to everybody who offered suggestions. Daniel T.'s comes
                          closest to what I was imagining, although I'm not surprised I didn't
                          manage it myself -- any of the solutions seem to be rather
                          complicated and non-intuitive.
                          Maybe it seems complicated at first, but after you have seen the
                          patterns a few times, it gets to be quite simple.

                          In each class' cpp file, I create a global object. The constructor of
                          the global objects created log themselves in yet another object (the
                          "models" object inside the "modelMap() " function.) "main" then accesses
                          the "models" map and calls create on the appropriate factory.

                          The only tricky part is making sure that the "models" object is
                          constructed before any of the factory objects are, that is why the
                          models object is embedded in a function.
                          Where should I be looking to learn how to write code like this?
                          This newsgroup is a good source. I strongly suggest the library as well.

                          First go to (http://accu.org/index.php/book_reviews) and find a few
                          books that you think might be useful, then write down their title,
                          author, and ISBN and take it to your local librarian. If your local
                          library doesn't have one or more of the books, tell the librarian that
                          you would like to do an inter-library loan.

                          Of course, if you find a book indispensable, go to the bookstore and buy
                          a copy.
                          I am interested in scientific programming applications, where the
                          same algorithm is applied to disparate models, and I'm thus
                          interested in learning how to increase the abstraction level of my
                          code (without sacrificing speed, of course!)
                          That is what the standard library is all about, a bunch of algorithms
                          that are applied to different models. I suggest starting there.

                          Comment

                          • David Sanders

                            #14
                            Re: Choosing a class using a variable without if-else


                            Daniel T. wrote:
                            "David Sanders" <dpsanders@gmai l.comwrote:
                            Daniel T. wrote:
                            I think it is important to note that the "extra work" you are
                            trying to avoid is adding 2 lines in your main every time you make
                            a new sub-class. That's not much...
                            >
                            In order to save you extra work in this case, the solution must
                            allow you to add a new class to main with only one line of extra
                            code, and the number of classes must be great enough to justify
                            the amount of code required to allow that one line to work.
                            Thanks again to everybody who offered suggestions. Daniel T.'s comes
                            closest to what I was imagining, although I'm not surprised I didn't
                            manage it myself -- any of the solutions seem to be rather
                            complicated and non-intuitive.
                            >
                            Maybe it seems complicated at first, but after you have seen the
                            patterns a few times, it gets to be quite simple.
                            >
                            In each class' cpp file, I create a global object. The constructor of
                            the global objects created log themselves in yet another object (the
                            "models" object inside the "modelMap() " function.) "main" then accesses
                            the "models" map and calls create on the appropriate factory.
                            >
                            The only tricky part is making sure that the "models" object is
                            constructed before any of the factory objects are, that is why the
                            models object is embedded in a function.
                            >
                            Where should I be looking to learn how to write code like this?
                            >
                            This newsgroup is a good source. I strongly suggest the library as well.
                            Your above description of the pattern you used is exactly the kind of
                            thing I'm interested in learning.
                            And it's exactly the kind of thing I don't know where to find. If you
                            have recommendations for specific books or book areas, I'd be very
                            grateful, since I do not have ready access to relevant books,
                            especially not to browse through, because of where I'm living.

                            For example, for the above trick/method, would I look in a book on C++
                            templates, on design patterns, or what? And what would I have searched
                            for in the newsgroup?

                            Thanks and best wishes,
                            David.

                            Comment

                            • collection60@googlemail.com

                              #15
                              Re: Choosing a class using a variable without if-else

                              You could try reverse engineering the RTTI :) Probably more hassle than
                              it's worth.

                              Comment

                              Working...