Структура данных, которая может содержать несколько типов данных - PullRequest
4 голосов
/ 08 июля 2010

Как видно из названия, я ищу какую-то структуру данных, которая позволила бы мне хранить в ней любой тип класса, который мне нужен в данный момент. Например:

Foo *foo = new Foo();
Bar *bar = new Bar();
someContainer.push_back( foo );
someContainer.push_back( bar );
someContainer.access( 0 )->doFooStuff();
someContainer.access( 1 )->doBarStuff();

В идеале, как я там показал, это также позволило бы мне получить доступ к содержимому и использовать их функции / и т.д.
Я хочу один из них, поскольку я пытаюсь создать «невидимую» систему управления памятью, которая просто требует, чтобы класс унаследовал мой класс диспетчера памяти, и все будет работать автоматически.
Вот пример того, как должен выглядеть код:

template< class T >
class MemoryManaged
{
   MemoryManaged()
   {
      container.push_back( this );
   }
   void *operator new()
   {
       // new would probably be overloaded for reference counting etc.
   }
   void operator delete( void *object )
   {
       // delete would most definitely overloaded
   }
   T &operator=( T &other )
   {
      // = overloaded for reference counting and pointer management
   }

   static SomeContainer container;
}

class SomeClass : public MemoryManaged< SomeClass >
{
   // some kind of stuff for the class to work
};
class AnotherClass : public MemoryManaged< AnotherClass >
{
   // more stuff!
};

Я надеюсь, что мой код поможет прояснить, что именно я хочу сделать. Если кто-то знает какую-то уже построенную структуру данных, которая позволила бы мне сделать это, это было бы здорово. В противном случае, я сейчас работаю над созданием какого-то зомби-зомби из связанного списка, который использует шаблонные узлы, чтобы связать любой тип класса с любым другим типом класса. Я до сих пор не знаю, как мне заставить его работать, и я бы хотел, чтобы его избавили от крови, пота и слез (и волос), которые понадобятся, чтобы понять, как заставить это работать.

Ответы [ 4 ]

4 голосов
/ 08 июля 2010

Есть общий базовый класс для всех ваших нескольких типов.Держите структуру данных за указатели типа вашего базового класса.

3 голосов
/ 08 июля 2010

Взгляните на boost::any и boost::variant.

1 голос
/ 08 июля 2010

Поможет ли какой-нибудь гибрид специализации шаблонов и двойной отправки? Примерно так:

class IContainable;
class Operation
{
public:
   template<class ElementType> void Process(ElementType* pEl) {
      // default is an unrecognized type, so do nothing
   }
};

class IContainable
{
public:
    virtual void OperateOn(Operation* pOperation) = 0;
};


class Foo : public IContainable
{
public:
    int GetFooCount() { return 1; }
    virtual void OperateOn(Operation* pOperation);
};

// specialization of the operation for Foo's
template <> void Operation::Process<Foo>(Foo* pFoo)
{
     std::cout << pFoo->GetFooCount() << std::endl; 
}

void Foo::OperateOn(Operation* pOperation)
{
   pOperation->Process(this);
}

int main()
{
    typedef std::vector<IContainable*> ElementVector; 
    ElementVector elements;
    // configure elements;
    Operation oper;
    for(ElementVector::iterator it = elements.begin(); 
         it != elements.end(); it++)
    {
        (*it)->OperateOn(&oper);
    }
}

Если список типов в контейнере неизвестен во время компиляции операций элементов в контейнере или они распределены по модулям, которые не скомпилированы вместе, тогда вы можете вместо этого использовать dynamic_cast. Вы бы определили класс «IFooHandler» с помощью чисто виртуального метода под названием «HandleFoo», который принимает указатель foo. Вы сделаете Operation :: Process виртуальным, и ваш класс операций будет производным как от Operation, так и от IFooHandler, и реализует операцию в HandleFoo (). Ваш метод Foo :: OperateOn имел бы dynamic_cast (pOperation), и если бы результат был ненулевым, он вызвал бы HandleFoo () для указателя IFooHandler, полученного из динамического приведения. В противном случае вы бы вызвали универсальный Operation :: Process, и он имел бы некоторое поведение, не зависящее от типа.

0 голосов
/ 08 июля 2010

Использование std::vector<T*> должно работать. Действительно, новый класс будет создаваться для каждого экземпляра MemoryManaged. Это означает, что MemoryManaged<Foo> и MemoryManaged<Bar> будут совершенно разных типов. Следовательно, статический член container не будет общим для этих двух классов . Это будет, как если бы у вас было два следующих класса:

class MemoryManagedFoo
{
    MemoryManagedFoo()
    {
        //Here, you know that 'this' is a Foo*
        container.push_back(this); //ok, we add 'this' to a container of Foo*
    }

    static std::vector<Foo*> container;
};

class MemoryManagedBar
{
    MemoryManagedBar()
    {
        //Here, you know that 'this' is a Bar*
        container.push_back(this); //ok, we add 'this' to a container of Bar*
    }

    static std::vector<Bar*> container;
};

Как видите, статический член не используется двумя экземплярами.

Конечно, это решение предполагает, что MemoryManaged всегда будет использоваться с использованием CRTP, как вы описали в своем вопросе. Другими словами, этот код будет работать:

class Foo : public MemoryManaged<Foo> { };

но не этот:

class Foo : public MemoryManaged<Bar> 
{
    // Here, 'container' is a 'vector<Bar*>' and 'this' is a Foo * --> problem
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...