C ++,oop,类列表(类类型)和创建它们的实例

时间:2009-12-10 20:40:13

标签: c++ oop

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

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

伪代码

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!

请提供任何提示......

6 个答案:

答案 0 :(得分:3)

您可以创建模板化工厂对象:

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)

答案 1 :(得分: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!

答案 2 :(得分:2)

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 );    

答案 3 :(得分:1)

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

例如:

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();

答案 4 :(得分:0)

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

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

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

答案 5 :(得分:0)

工厂模式可行(参见例如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作为静态int嵌入到类声明中通常是一个好的开始。