2009-12-10 3 views
1

클래스가 많이 선언되어 있고, 모두 기본 클래스 (상속 클래스)로부터 상속됩니다. 내가 사용하고 싶습니다 일반적인 방법 ...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! 
,536,

팁을주세요 ...

+0

런타임에 정의 된 유형의 목록입니다하거나 컴파일에서 알려져 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 수율을 실행 일할 수 시각? –

+0

당신이 무엇을 요구하고 있는지 명확하지 않지만, 클래스 계층의 인스턴스를 다룰 때는 값의 모음이 아닌 POINTERS의 콜렉션을 사용해야 만합니다. –

+0

구현 된 모든 유형의 목록은 컴파일 타임에 알려져 있습니다. 하지만 내가 사용해야하는 클래스 인스턴스는 입력 데이터에 따라 다릅니다. 따라서 새로운 상속 클래스를 추가 할 때 시간을 절약하기 위해 자동화하고 싶습니다. – migajek

답변

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) 
+0

와우 ... 나는 C++에서 초보자 일세. IBaseType이나 "std :: transform"라인을 구조화하지 못한다. : – migajek

+0

IBaseType은 내 추상화 버전이다. std :: transform'은 단지 show-off 일 뿐이며'factories'의 각 팩토리에서'create'를 호출하고 그 결과를'objects' 벡터의 뒤쪽에 넣습니다. 가끔은 사용하기 쉽지만 실제로는 사용하지 않습니다 :) – xtofl

0

당신은 abstract 타입의 포인터 목록을 가지고 있어야합니다. null에 대한 모든 포인터를 초기화하고 나중에 올바른 클래스로 구성하십시오. 미리 포인터를 미리 입력 할 필요가 없습니다. 후자는 RTTI에만 의존 할 수 있습니다.

유형을 미리 입력하기 전에 사전 입력해야하는 경우 유형에 enum ~ Abstract을 추가하십시오. 상속 된 클래스가 클 경우 메모리를 절약 할 수 있습니다. 하지만 당신은 유형의 열거 형을 유지해야합니다. 일을하는 가장 우아한 방법이 아닙니다.

초기화하고 사전 입력해야하는 경우 기본 생성자를 사용하여 클래스를 초기화하면됩니다. 그러나이 방법은 필요하지 않을 때 메모리를 사용하고 있습니다. 여기 RTTI가 당신의 친구가 될 것입니다.

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 
    } 
} 

추가 작업으로 상당히 우아해질 수 있습니다. static int로 클래스 선언에 클래스 ID를 임베드하는 것은 종종 좋은 시작입니다.

1

저는 공장 기반 디자인을 사용하는 것이 좋습니다. 당신의리스트는 많은 factory 인스턴스들을 저장하고, 당신은 올바른 factory 메소드를 호출함으로써 Abstract-derived 인스턴스를 생성 할 수 있습니다. 예를 들어

:

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

Boost.MPL을 단순화한다. 하산시에 들리지 마.

예 :

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

편집 :

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

당신의 코드가 좀 더 융통성이 있거나 뭐든지 될 수 있다고 생각하지만, 너무 복잡해지기 때문에 컴파일을 위해 부스트가 필요합니다. 나는 피하고 싶습니다 ...하지만 고맙습니다. 언젠가는 고맙겠습니다.) :) – migajek

+0

@michal 이해합니다. MPL은 매우 어려울 수 있으며 쓰기가 끝난 후 6 개월이 더 힘들어 질 수도 있습니다. 물론 Boost.PP는 전처리기에 의존하고 사람들이 매크로를 비합리적으로 증오하므로 순수한 악마입니다. – KitsuneYMG

+0

전 단지 전처리 기 모듈에서 bcp를했고 완전히 자체적으로 포함되어 있습니다 (최소한 bcp는 그렇게 생각합니다). 전체가 너무 많은 경우 부스트 부분 만 사용할 수 있습니다. – KitsuneYMG