2012-01-05 2 views
0

В моей программе, я нахожу ситуацию, в которой я хочу UserClass чтоКак создать класс, содержащий разные типы классов, и вызвать членов этих объектов?

  1. представляет собой контейнер, который может содержать разнородные типы
  2. могут вызывать функции-члены объектов, проводимых.

Набор типов, которые хранятся, ограничен и известен во время компиляции. На самом деле, все типы просто отличаются от template специализаций.

Этот код иллюстрирует ситуацию:

class ArrayBase { /*etc.*/ }; // definition not changeable 

template <class T> 
class TypedArray : public ArrayBase // definition not changeable 
{ 
/*more functionality needed by SpecializedArray.*/ 
} 

template<class T> 
class SpecializedArray : public TypedArray<T> 
{ 
public: 
void newFunctionalityMember() { /*etc.*/ }; 
}; 

class UserClass 
{ 
    addArray(arrayElmentTypeEnum_t t) 
    { 
     switch(t) { 
     case float_id: 
      _elementArrays.push_back(new SpecializedArray<float>()); 
      break; 
     case double_id: 
      _elementArrays.push_back(new SpecializedArray<double>()); 
      break; 
     default: 
      break; 
    } 

    void doSomethingWithASpecializedArray(int num) 
    { 
     // using _elementArrays[num], call the correct newFunctionalityMember() 

    } 

    private: 
     std::vetor<storagePtr_t> _elementArrays; 
} 

Без какой-то мольбы, я не имею возможность изменить ArrayBase или TypedArray. Я оставил storagePtr_t Тип неопределенный, поскольку какой тип он должен быть, является ключевой частью моего вопроса.

Я могу придумать одно решение, показанное ниже. Но какая боль! Это очень много кода, чтобы иметь в любом месте UserClass, что мне нужно получить доступ к элементам элемента. Есть ли лучший способ?

boost library is fair game.

моя техника:

storagePtr_t является ArrayBase*, arrayElmentTypeEnum_t будет std::type_info*

UserClass::doSomethingWithASpecializedArray(int num) 
{ 
// these two both uniquely identified by num. 
storagePtr_t * bptr = _elementArrays[num]; 
arrayElmentTypeEnum_t typekey = ... 

    if  (typekey == &typeid(SpecializedArray<float>)) { 
     D<float> * dptr = static_cast<SpecializedArray<float>*>(bptr); 
     dptr->newFunctionalityMember(); 
    } else if (typekey == &typeid(SpecializedArray<double>)) { 
     D<float> * dptr = static_cast<SpecializedArray<double>*>(bptr); 
     dptr->newFunctionalityMember(); 
    } else if (typekey == &typeid(SpecializedArray<int>)) { 
     D<float> * dptr = static_cast<SpecializedArray<int>*>(bptr); 
     dptr->newFunctionalityMember(); 
    } 
} 
+0

к сожалению, я нашел мой ранее [вопрос] (http://stackoverflow.com/questions/8736923/cast-base-class-pointer-to - на основе одного из нескольких возможных вариантов-типа-указателя) не содержало достаточно подробностей моего дела, чтобы вымыть полезное решение. – NoahR

+1

Почему вы не можете использовать 'UserClass' также' template'? Это спасет вас от множества беспорядков, не так ли? – iammilind

ответ

2

Вы могли бы ввести новый базовый класс, который определяет интерфейс, который вы хотите вызвать:

class SpecializedArrayBase { 
public: 
    virtual ~SpecializedArrayBase() {} 
    virtual void newFunctionalityMember() = 0; 
}; 

, а затем получить Ваш тип массива из этой базы:

template<class T> 
class SpecializedArray : public TypedArray<T>, public SpecializedArrayBase 
{ 
public: 
    void newFunctionalityMember() { /*etc.*/ }; 
}; 

Затем вы можете хранить объекты в векторе по новому базовому типу SpecializedArrayBase:

typedef SpecializedArrayBase* storagePtr_t; 

Поскольку базовый класс определяет функцию, которую вы хотите вызвать, вы можете избежать всех литья и вызвать его через базовый указатель:

void doSomethingWithASpecializedArray(int num) 
{ 
    for (size_t i = 0; i < _elementArrays.size(); ++i) { 
     _elementArrays[i]->newFunctionalityMember(); 
    } 
} 
+0

Спасибо @DRH! это работает красиво. Я не думал о наследовании от двух классов. Возможно, стоит отметить, что 'SpecializedArrayBase' должен иметь виртуальный деструктор, или деструктор' UserClass' должен быть очень явным, чтобы удостовериться, что вызываются деструкторы 'SpecializedArray'. – NoahR

+0

Спасибо @NoahR, я добавил виртуальный dtor к примеру. – DRH