Как сделать так, чтобы класс содержал разные типы классов и вызывал членов этих объектов? - PullRequest
0 голосов
/ 05 января 2012

В моей программе я нахожу ситуацию, когда я хочу 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, что мне нужно для доступа к элементам элемента. Есть ли лучший способ?

библиотека повышения - это честная игра.

моя техника:

storagePtr_t is 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();
    }
} 

1 Ответ

2 голосов
/ 05 января 2012

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

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();
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...