【问题标题】:C++, oop, list of classes (class types) and creating instances of themC++,oop,类列表(类类型)并创建它们的实例
【发布时间】:2009-12-10 20:40:12
【问题描述】:

我声明了很多类,它们都继承自一个基类(某种抽象)......所以它们都有我想使用的通用方法......

现在,我需要一个 classesnot 对象)的列表,然后在循环中创建它们的实例,并使用这些实例来调用提到的常用方法。 ..

伪代码

class Abstract {
 void Something();
}

class TaskOne : public Abstract {
 void Something(); // method implemented somewhere below
}

class TaskTwo : public Abstract {
 void Something(); // method implemented somewhere below
}


...

list<Abstract> lst;

lst.push_back(TaskOne); // passing class type, not instance!
lst.push_back(TaskTwo); 

Abstract tmpObject = new lst[0]; //I know its wrong, just a way of expressing what I'd like to do to have instance of TaskOne!

请给点建议...

【问题讨论】:

  • Boost MPL 是一种方法。见http://stackoverflow.com/questions/1185464
  • MPL 实在是太矫枉过正了,要一个人必须是虐待狂才能学习它(我就是其中之一)。
  • 类型列表是在运行时定义的还是在编译时已知的?
  • 不清楚你在问什么,但在处理类层次结构的实例时,你必须使用指针集合而不是值。
  • 所有实现类型的列表在编译时是已知的。但是我需要使用哪些类实例取决于输入数据。因此,我想在添加新的继承类时将其自动化以节省时间。

标签: c++ oop


【解决方案1】:

你可以创建一个模板化的工厂对象:

struct IFactory { virtual IBaseType* create() = 0; };

template< typename Type > struct Factory : public IFactory {
   virtual Type* create( ) {
      return new Type( );
   }
};

struct IBaseType { /* common methods */ virtual ~IBaseType(){} };

IFactory* factories[] = {
  new Factory<SubType1>
, new Factory<SubType2>
// ...
};

std::vector<IBaseType*> objects;
objects.push_back( factories[1]->create() ); // and another object!

// don't forget to delete the entries in the 
// vector before clearing it (leak leak)

【讨论】:

  • 哇...我是 C++ 的新手,不太了解 struct IBaseType 是什么,也没有“std::transform”行... :(
  • IBaseType 是我的Abstract 版本。 std::transform 只是炫耀:它在factories 中的每个工厂上调用create,并将结果放在objects 向量的后面。有时很方便,但在这里没用,真的:)
【解决方案2】:

我会使用模板化工厂,比如 xtofl proposed,但要简化它的使用

struct IFactory { virtual IBaseType* create() = 0; };

template< typename Type > struct Factory : public IFactory {
   virtual Type* create( ) {
      return new Type( );
   }
};

list<IFactory*> lst;

lst.push_back(new Factory<TaskOne>); 
lst.push_back(new Factory<TaskTwo>); 

Abstract *tmpObject = lst[0]->create();

// don't forget to delete all the factory instances!

【讨论】:

    【解决方案3】:

    Boost.MPL 这里的答案。不要听 Hassan Syed 的。

    例子:

    namespace mpl=boost::mpl;
    typedef mpl::vector< CLASS1, CLASS2,...,CLASSN > class_list_a;
    typedef mpl::push_back< class_list_a ANOTHER_CLASS>::type class_list_b;
    typedef mpl::push_back<
        typename mpl::push_back<
            class_list_b,
            ANOTHER_TYPE_1>::type, 
        ANOTHER_TYPE_2>::type
    class_list;
    
    struct functor {
        template<class U> void operator(U& u) {
            u.something();
        }
    };
    ...
    // in some function
    boost::mpl::for_each<class_list>( functor() );
    

    编辑:BOOST_PP 也可以工作

    #include <boost/preprocessor/cat.hpp>
    #include <boost/preprocessor/seq/for_each.hpp>
    #define MY_CLASSES (TYPE_1)(TYPE_2)(TYPE_N)
    #define MY_FUNCTION(r, data, elem) elem() . data;
    #define CALL_SOMETHING_ON(_CLASSES_, _ARGS_) \
        BOOST_PP_SEQ_FOR_EACH( MY_FUNCTION, someThing( _ARGS_ ), _CLASSES_ )
    int foo = 1;
    CALL_SOMETHING_ON( MY_CLASSES, foo )
    

    运行cpp foo.c 产生:

    int foo = 1;
    TYPE_1() . someThing( foo ); \
    TYPE_2() . someThing( foo ); \
    TYPE_N() . someThing( foo );    
    

    【讨论】:

    • 我相信你的代码可能更灵活或其他什么,但它对我来说太复杂了,需要 Boost 进行编译——我想避免这种情况......但是谢谢,可能有一天我会很感激的:) :)
    • @michal 我明白了。 MPL 在你编写 6 个月后可能很难理解,甚至更难。 Boost.PP 的东西当然是纯粹的邪恶,因为它依赖于预处理器,而且人们对宏有一种莫名其妙的仇恨。
    • 我刚刚在预处理器模块上做了一个 bcp,它是完全独立的(至少 bcp 是这么认为的)。如果整体太多,你可以只使用提升的那一部分。
    【解决方案4】:

    我建议使用基于工厂的设计。您的列表存储了一堆工厂实例,您可以通过调用正确的工厂方法来创建抽象派生实例。

    例如:

    class Abstract
    {
        virtual void Something() = 0;
    };
    
    class TaskOne : public Abstract
    {
        void Something();
    };
    
    class AbstractFactory
    {
    public:
        Abstract* CreateInstance();
    };
    
    template <class T> class Factory : public AbstractFactory
    {
    public:
        Abstract* CreateInstance()
        {
            return new T();
        }
    };
    
    ...
    
    std::vector<AbstractFactory*> Factories;
    
    Factories.push_back(new Factory<TaskOne>());
    
    ...
    
    Abstract *Instance = Factories[ 0 ]->CreateInstance();
    

    【讨论】:

      【解决方案5】:

      工厂模式可以工作(参见例如http://en.wikipedia.org/wiki/Factory_method_pattern)。大致如下:

      #define stringify(a) #a
      static int hashstr(const char* s) {/*hash fn of choice*/}
      
      list<int> types;
      
      lst.push_back(hashtr(stringify(TaskOne))); // passing class type, not instance!
      lst.push_back(hashtr(stringify(TaskTwo))); 
      
      static Abstract* Instance(int classid)
      {
        switch(id)
        {
        case hashstr(stringify(TaskOne)):
          return new TaskOne;
        //etc
        }
      }
      

      你可以通过额外的工作变得更加优雅。将类 ID 作为静态整数嵌入到类声明中通常是一个好的开始。

      【讨论】:

        【解决方案6】:

        你需要有一个抽象类型的指针列表。将所有指针初始化为 null 并稍后构造到正确的类。您无需预先输入指针。你可以只依赖RTTI 后者。

        如果您确实需要预先输入它们,而不仅仅是为这些类型添加一个enumAbstract。如果继承的类很大,这可以节省内存。但是你必须自己维护类型的枚举,而不是最优雅的做事方式。

        如果您必须初始化并预先键入它们,只需使用默认构造函数初始化类即可。但是这样你在不需要时使用内存。在这种情况下,RTTI 将成为您的朋友。

        【讨论】:

          猜你喜欢
          • 2017-04-10
          • 2021-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-04
          • 1970-01-01
          • 2021-12-12
          相关资源
          最近更新 更多