class data_base_t
{
}
class data_t : public data_base_t
{
}
class storage_base_t
{
}
class storage_t : public storage_base_t
{
some_collection<data_t> m_data;
}
Есть ли какие-нибудь стандартные бииблиотеки для того, чтобы работать с m_data из storage_base_t (само собой там данные должны быть типа data_base_t&) ?
Или самому надо писать?
Здравствуйте, anatoly1, Вы писали:
A>Есть ли какие-нибудь стандартные бииблиотеки для того, чтобы работать с m_data из storage_base_t (само собой там данные должны быть типа data_base_t&) ? A>Или самому надо писать?
boost::ptr_vector ?
Прежде чем искать или писать, определись с ко/контра/инвариантностью типов элементов.
То есть, понятно, что предок не знает про конкретные элементы. Но может ли он записать в контейнер что-то своё, например? Может ли он вообще делать присваивание? (это самая примитивная контравариантность, разрешённая в С++, и по дефолту ведущая к срезке).
Здравствуйте, anatoly1, Вы писали:
A>А чего нибудь наподобие data_accessor_t нету?
Готового — не знаю.
А сделать своё — легко.
template<class T>
class derived_array
{
char* data_; //
size_t step_; // шаг (размер элемента в байтах)
size_t size_; // размер массива (в элементах)public:
template<class U>
derived_array(U* data, size_t num) : data_((char*)data), size_(num) { STATIC_ASSERT(is_base_and_derived<T,U>::value); }
size_t size() const { return size_; }
T& operator [] (size_t i) const { return (T*)(data_ + i*step_); }
// итератор слепить из boost::iterator_adaptor - как два пальца об асфальт
};
Тут ещё вопрос возникнет — а что нужно в интерфейсе этого фасада к контейнеру.
Только доступ по индексу?
Итераторы STL?
Возможность менять размер (создавая и удаляя элементы фактического типа)?
Здравствуйте, Кодт, Вы писали:
К>Тут ещё вопрос возникнет — а что нужно в интерфейсе этого фасада к контейнеру. К>Только доступ по индексу? К>Итераторы STL? К>Возможность менять размер (создавая и удаляя элементы фактического типа)?
Желательно, конечно, возможностей по максимому.
Потому и спрашиваю про готовые решения: может где-то уже это всё есть.
Здравствуйте, anatoly1, Вы писали:
A>Предположим, есть такая конструкция:
A>
A>class data_base_t
A>{
A>}
A>class data_t : public data_base_t
A>{
A>}
A>class storage_base_t
A>{
A>}
A>class storage_t : public storage_base_t
A>{
A> some_collection<data_t> m_data;
A>}
A>
A>Есть ли какие-нибудь стандартные бииблиотеки для того, чтобы работать с m_data из storage_base_t (само собой там данные должны быть типа data_base_t&) ? A>Или самому надо писать?
Меня бы насторожило, что вы хотите в базовом классе работать с данными наследника, скорее всего что-то не так с архитектурой.
Скорее всего вам просто нужен некий хелпер-класс, или набор внешнего хелпер-апи. storage_base_t подразумевает семейство классов с общим интерфейсом, вот и не надо тащить в него детали реализации.
Здравствуйте, saf_e, Вы писали:
_>Меня бы насторожило, что вы хотите в базовом классе работать с данными наследника, скорее всего что-то не так с архитектурой.
Ну в идеале, конечно, хотелось бы нечто вроде:
class storage_base_t
{
some_collection<data_base_t> m_data;
}
Только в C++ так не получится.
А коллекцию указателей создавать не хочется.
Здравствуйте, anatoly1, Вы писали:
A>Ну в идеале, конечно, хотелось бы нечто вроде: A>
A>class storage_base_t
A>{
A> some_collection<data_base_t> m_data;
A>}
A>
A>Только в C++ так не получится. A>А коллекцию указателей создавать не хочется.
Проблема архитектурная, а не сиплюсплюсная.
Специально пугаю страшными словами: ковариантность, контравариантность, инвариантность.
Особенно остро этот вопрос возникает в яве и дотнете, хотя присущ ООП вообще.
Если же не пугаться, то просто ответь себе и нам:
— кто определяет тип элементов (наследник или база)
— кто наполняет коллекцию
— кто этим наполнением пользуется
И кстати, сколько наследников в иерархии предполагается иметь. И предполагается ли наследование от наследников.
По-хорошему, у наследника должна быть some_collection<data_t> и интерфейс к предку, отдающий some_view<data_base_t> на эту коллекцию.
Что входит в some_view — только size() и operator[], или ещё что-то — сам решай.
Можно ценой некоторого провала производительности сделать коллекцию, которая в рантайме переключается на использование data_t вместо data_base_t, и бьёт по пальцам за запись туда чего-то отличного от data_t.
Можно ценой тщательного мытья рук — и опять же провала производительности — взять полиморфную коллекцию, наподобие boost::ptr_vector.
Вот там все проблемы ко-контра-вариантности вылезут в полный рост.
Здравствуйте, Кодт, Вы писали:
К>Проблема архитектурная, а не сиплюсплюсная.
В сишарпе такой проблемы нет, т.к. там используется pointer semantics (т.е. фактически boost::ptr_vector).
К>Если же не пугаться, то просто ответь себе и нам: К>- кто определяет тип элементов
наследник
К>- кто наполняет коллекцию
наследник
К>- кто этим наполнением пользуется
база
К>И кстати, сколько наследников в иерархии предполагается иметь.
Как минимум два.
К>И предполагается ли наследование от наследников.
Нет.
К>Можно ценой тщательного мытья рук — и опять же провала производительности — взять полиморфную коллекцию, наподобие boost::ptr_vector. К>Вот там все проблемы ко-контра-вариантности вылезут в полный рост.
Скорее всего остановлюсь на vector< unique_ptr<data_base_t> >.
Здравствуйте, Mr.Delphist, Вы писали:
MD>А в чём смущение? Идиома не накладывает тяжких ограничений или зависимостей, полная гибкость в реализации — что ещё надо?
В том, что владелец объекта storage_base_t (или storage_t) должен тогда тоже быть шаблонным.