По тому, как вы формулируете вопрос, это нечто невозможное:
vetor<Base>
содержит последовательность Base
с, в то время как First
и Second
оба Base
плюс что-то большее.
По своей природе вектор содержит последовательность идентичных объектов (все базы) и push_back, фактически не помещает объект внутри вектора, но копирует объект в тот, который построен в конце вектора (и является Base
объектом, поэтому копируется только подкомпонент Base
).
Чтобы решить эту проблему, вы должны сделать так, чтобы ваш вектор «не содержал» Base
-s, а «ссылался на» Base-s. Это требует указателей
std::vector<Base*> v;
v.push_back(new First);
v.push_back(new Second);
Но для этого также необходимо управление памятью. Это можно сделать двумя способами:
1) использовать какой-нибудь смарт-указатель, который «владеет» базой.
В C ++ 11 есть std::shared_ptr
и std::unique_ptr
.
В C ++ 03 вы должны расположить указатель подсчета ссылок как
template<class T>
class ptr
{
public:
ptr() :p(), c() {}
explicit ptr(T* z) :p(z), c(new unsigned(1)) {}
ptr(const ptr& s) :p(s.p), c(s.c) { if(c) ++*c; }
ptr& operator=(const ptr& s)
{
if(this!=&s)
{
if(c && !--*c) { delete p; delete c; }
p = s.p; c=s.c;
if(c) ++*c;
}
return *this;
}
~ptr() { if(c && !--*c) { delete p; delete c; } }
T* operator->() const { return p; }
T& operator*() const { return *p; }
private:
T* p;
unsigned* c;
};
и объявите свой вектор как
std::vector<ptr<Base> > v;
v.push_back(ptr(new First));
v.push_back(ptr(new Second));
v[0]->test();
v[1]->test();
Уничтожение v
, уничтожит ptrs, которые, в свою очередь, уничтожат объекты.
ПРИМЕЧАНИЕ: База также должна объявить виртуальный деструктор , иначе производный объект не может быть плиморфно уничтожен.
2)
В качестве альтернативы, вы можете «настроить» вектор на «собственный» указатель.
это может быть получено чем-то вроде
template<class T>
class owningvector: public std::vector<T*>
{
public:
~owningvector()
{
for(size_t i=0; i<size(); ++i)
delete at(i);
}
owningvector() {}
private:
//disable vector copy and assign
owningvector(const owningvector&);
owningvector& operator=(const owningvector&);
};
owningvector<Base> ov;
ov.push_back(new First);
ov.push_back(new Second);
ПРИМЕЧАНИЕ: Base
все еще нужен виртуальный деструктор.
Кроме того, будучи std::vector
и ownvector
не полиморфными при разрушении, не используйте себя как полиморфные типы.
* 1 042 * 3)
Если вы все делаете на_стаке, вы можете очень легко сделать
int main()
{
First first;
Second second;
std::vector<Base*> v;
v.push_back(&first);
v.push_back(&second);
v[0]->test();
v[1]->test();
//no other memory management is required:
// v is destroyed without doing anything special.
// second and first are destroyed just further.
}