Хранение разнородных объектов в векторе с выделенными стеком объектами - PullRequest
3 голосов
/ 21 октября 2009

Хранение объектов в разнородном векторе с выделенными в стеке объектами

Здравствуйте,

Скажем, у меня есть абстрактный класс CA, производный от CA1, CA2 и, возможно, других.

Я хочу поместить объекты этих производных типов в вектор, который я встроил в класс CB. Чтобы правильно понять полиморфизм, мне нужно сохранить вектор указателей:

class CB
{
    std::vector <CA*> v;
};

Теперь, скажем, у меня есть следующая основная функция:

int main()
{
    CB b;
    CA1 a1;
    CA2 a2;
    b.Store( a1 );
    b.Store( a2 );
}

Как мне написать метод void CB::Store(const CA&) простым способом, чтобы сохраненные объекты выживали, когда исходные объекты уничтожались (чего не происходит в простом примере выше).

Моя проблема в том, что мне нужно сначала скопировать объекты в куче, прежде чем копировать их адрес в векторе, но как я могу создать объект производного типа? Конечно, я мог бы использовать RTTI и искать все возможные типы, создавать и выделять указатель и копировать (при правильном приведении) объект в выделенное пространство, прежде чем помещать его в вектор. Но это кажется довольно сложным, нет?

Есть ли более простой способ?

(И без использования динамического выделения в основном!)

Ответы [ 3 ]

7 голосов
/ 21 октября 2009

Обычно вы предоставляете функцию клона:

struct CA
{
    virtual CA *clone(void) const = 0;
    virtual ~CA() {} // And so on for base classes.
}

struct CA1 : public CA
{
    virtual CA *clone(void) const
    {
        return new CA1(*this);
    }
}

struct CA2 : public CA
{
    virtual CA *clone(void) const
    {
        return new CA2(*this);
    }
}

Это называется виртуальный конструктор , вы можете создавать копии объектов во время выполнения:

void CB::Store(const CA& pObject)
{
    CA *cloned = pObject.clone();
}

Вам следует рассмотреть возможность использования библиотеки Boost.Pointer Container . Ваш код будет:

boost::ptr_vector<CA> objects;

void CB::Store(const CA& pObject)
{
    objects.push_back(pObject->clone());
}

И теперь вам не нужно самостоятельно управлять памятью. Библиотека также уважает функции клонирования и будет вызывать ее при создании копий ваших объектов. Учебник здесь .

2 голосов
/ 21 октября 2009

Похоже, вам нужна функция clone () в вашем абстрактном классе, которую будут реализовывать ваши производные классы.

class CA
{
   public:
   virtual ~CA() {}
   virtual CA* clone() const = 0;
}

class CA1 : public CA
{ 
    public:
    virtual CA *clone() const
    {
       return new CA1(*this);
    }
};
1 голос
/ 21 октября 2009

Можно было бы шаблонизировать Store по типу его аргумента:

class CB
{
public:
    template<class T>
    void Store(const T& t)
    {
         v.push_back(new T(t));
    }

private:
    std::vector <CA*> v;
};

Предупреждение: в отличие от решения "clone ()", опубликованного другими, оно склонно к нарезке. Например, это прекрасно работает:

CB b;
CA1 a1;
CA2 a2;
b.Store(a1);
b.Store(a2);

Но это не так:

CA1 a1;
CA* a = &a1;
b.Store(*a); //Ouch! this creates a new CA, not a CA1

Предоставление защищенной копии ctor для CA предотвращает такое неправильное использование. Однако если мы продолжим подкласс CA1, проблема вернется.

...