Dynamically creating an instance of a class from a string containing the class name in C++

后端 未结 7 2119
予麋鹿
予麋鹿 2020-12-31 09:00

Lets say I have a base class with 100 children:

class Base { 
  virtual void feed();
  ...   
};
class Child1 : public Base {
  void feed();  //specific proc         


        
7条回答
  •  清酒与你
    2020-12-31 09:51

    Behold the mighty Boost.

    The one thing you have to do in order to use my solution is to add a new member to all your classes, and that is a static const string that contains the name of the class. There are probably other ways to do it too, but that's what I have right now.

    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    using namespace std;
    using boost::fusion::cons;
    
    
    class Base { virtual void feed(){ } };
    
    class Child1 : public Base{
      void feed(){ }
    
    public:
      static const string name_;
    };
    const string Child1::name_ = "Child1";
    
    class Child3 : public Base{
      void feed(){ }
    
    public:
      static const string name_;
    };
    const string Child3::name_ = "Child3";
    
    //...
    class Child100 : public Base{
    
      void feed(){ }
    
    public:
      static const string name_;
    };
    const string Child100::name_ = "Child100";
    
    // This is probably the ugliest part, but I think it's worth it.
    typedef cons > > MyChildClasses;
    
    typedef vector Children;
    typedef vector Names;
    
    struct CreateObjects{      // a.k.a convert_string_to_instance() in your example.
    
      CreateObjects(Children& children, string name) : children_(&children), name_(name){ }
    
      template 
      void operator()(T& cs) const{
    
        if( name_ == cs.name_ ){
          cout << "Created " << name_ << " object." << endl;
          (*children_).push_back(new T);
        }else{
          cout << name_ << " does NOT match " << cs.name_ << endl;
        }
      }
    
      Children* children_;
      string name_;
    };
    
    int main(int argc, char* argv[]){
    
      MyChildClasses myClasses;
    
      Children children;
      Names names;
      names.push_back("Child1");
      names.push_back("Child100");
      names.push_back("Child1");
      names.push_back("Child100");
    
      // Extra test.
      // string input;
      // cout << "Enter a name of a child class" << endl;
      // cin >> input;
      // names.push_back(input);
    
      using namespace boost::fusion;
      using boost::fusion::begin;
      using boost::fusion::for_each;
    
      for(Names::iterator namesIt = names.begin(); namesIt != names.end(); ++namesIt){
    
        // You have to know how many types there are in the cons at compile time.
        // In this case I have 3; Child1, Child3, and Child100
        boost::fusion::iterator_range<
          result_of::advance_c::type, 0>::type,
          result_of::advance_c::type, 3>::type
          > it(advance_c<0 >(begin(myClasses)),
           advance_c<3>(begin(myClasses)));
        for_each(it, CreateObjects(children, *namesIt));
      }
    
      cout << children.size() << " objects created." << endl;
      return 0;
    }
    

提交回复
热议问题