Мне было интересно, существует ли элегантное решение этой проблемы.Полиморфизм в контейнерах ST ++ STL
Предположим следующее:
class Base {
private:
int data;
protected:
Base(int data) : data(data) { }
int getData() const { return data; }
virtual bool someOp() = 0;
}
class Derived1 : public Base {
private:
int data2;
public:
Derived1(int data, int data2) : Base(data), data2(data2) { }
int getData2() const { return data2; }
bool someOp() override { /* something */ }
}
class Derived2 : public Base {
private:
float data2;
public:
Derived1(int data, float data2) : Base(data), data2(data2) { }
float getData2() const { return data2; }
bool someOp() override { /* something */ }
}
И предположим, что у меня есть полный контроль над иерархией, поэтому я могу предположить, что Base
не будут расширены, ни DerivedX
класса.
Теперь я хочу сохранить их в std::vector
, если я хочу использовать полиморфизм, я вынужден хранить указатели, иначе наложение объектов не позволит мне хранить дополнительные производные свойства. Поэтому я в основном вынужден использовать std::vector<unique_ptr<Base>>
.
Но давайте предположим, что мне нужно хранить большое количество этих объектов, и я не хочу тратить для двойного выделения кучи (внутренний std::vector
+ сам объект), и что в то же самое время, я могу предположить, что:
- иерархия классов прекрасно определяется и не будет продлен, не зная, что
sizeof(DerivedX)
не будет таким большим, чемsizeof(Base)
так мне интересно, если есть элегантный способ сохранять полиморфизм и избегать хранения указателей. Я мог бы подумать о некоторых решениях, таких как
class Base {
enum {
DERIVED1,
DERIVED2
} type;
int data;
union {
int derived1data;
float derived2data;
}
bool someOp() {
if (this->type == DERIVED1) ...
else if ..
}
}
Но это явно не изящно. Я мог бы также попытаться использовать тот факт, что разбиение объектов не должно происходить, если sizeof(Derived) == sizeof(Base)
с использованием защищенного объединения в Base
и доступа к нему от Derived
и литья адреса в элементы в std::vector
до нужного типа (в соответствии с перечислением), но это Звучит некрасиво.
Вы можете взглянуть на буст :: вариант ... – Deduplicator
Да, 'повышение :: variant', а связанный с ним' apply_visitor' что пришло на ум для меня. Однако вам нужно знать все производные типы заранее. –
Связь между базой и DerivedX не имеет значения при использовании boost_variant. Также может быть N несвязанных классов. –