Хранение разнородных объектов в векторе с объектами, выделенными стеком
-
05-07-2019 - |
Вопрос
Хранение объектов в разнородном векторе с объектами, выделенными стеком
Здравствуйте,
Допустим, у меня есть абстрактный класс 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 и выполнить поиск по всем возможным типам, создать и выделить указатель и скопировать (с надлежащим приведением) объект в выделенное пространство, прежде чем поместить его в вектор.Но это кажется довольно сложным, не так ли ?
Есть ли более простой способ ?
(И без использования динамического распределения в основном !)
Решение
Как правило, вы предоставляете функцию клонирования:
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::ptr_vector<CA> objects;
void CB::Store(const CA& pObject)
{
objects.push_back(pObject->clone());
}
И теперь вам не нужно самостоятельно управлять памятью.Библиотека также уважает функции клонирования и будет вызывать их при создании копий ваших объектов. Учебное пособие здесь.
Другие советы
Похоже, вам нужна функция clone() в вашем абстрактном классе, которую будут реализовывать ваши производные классы.
class CA
{
public:
virtual ~CA() {}
virtual CA* clone() const = 0;
}
class CA1 : public CA
{
public:
virtual CA *clone() const
{
return new CA1(*this);
}
};
Одной из возможностей было бы шаблонизировать хранилище в зависимости от типа его аргумента:
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 центру сертификации предотвращает такое неправильное использование.Однако, если мы продолжим подкласс CA1, проблема вернется.