Рассмотрим следующие классы
class Base {
public:
virtual void do_stuff() = 0;
};
class Derived : public Base {
public
virtual void do_stuff() { std::cout << "I'm useful"; };
};
Теперь скажем, что я хочу иметь еще один класс, ответственный за владение объектами Base
производных типов и перебирать их, называя их метод do_stuff()
. Это похоже на это, но я не знаю, что T
следует объявить как
class Owner {
public:
void do_all_stuff() {
//iterate through all items and call do_stuff() on them
}
void add_item(T item) {
items.push_back(item);
}
vector<T> items;
}
Я вижу несколько возможностей:
T
не может быть Base
, так как я мог бы только добавлять объекты конкретного типа Base
, так что не может быть и речи.
T
может быть Base*
или Base&
, но теперь мне нужно доверять вызывающему устройству add_item()
, чтобы передать мне указатель или ссылку на объект, который будет существовать, когда я его извлечу из items
. Я не могу delete
элементы в деструкторе Owner
, так как я не знаю, что они были динамически распределены. Однако они должны быть delete
'd, если бы они были, что оставляет меня с двусмысленным владением.
T
может быть Base*
или Base&
, и я добавляю метод Base* create_item<DerivedT>() { return new DerivedT; }
к Owner
. Таким образом, я знаю, что указатель останется в силе, и я его сохраню, но я не могу вызвать конструктор не по умолчанию на DerivedT
. Кроме того, Owner
становится ответственным за создание экземпляров объектов. Я также должен удалить каждый элемент в деструкторе Owner
, хотя это и не проблема.
В принципе, я хотел бы сделать что-то похожее на:
Owner owner;
void add_one() {
Derived d;
owner.add_item(d);
}
void ready() {
owner.do_all_stuff();
}
void main() {
for(int i = 0; i < 10; ++i) {
add_one();
}
ready();
}
Я уверен, что там что-то связано с семантикой перемещения (я мог перемещать объекты, переданные в add_items()
, чтобы их владеть), но я до сих пор не могу понять, как будет объявлена моя коллекция.
Что такое идиома С++ для такого рода полиморфного владения (в частности, с контейнерами STL)?