У меня есть класс, который использует несколько политик, которые являются шаблонными. Это называют Dish
в следующем примере. Я храню многие из них Dish
es в a vector
(использование указателя на простой базовый класс), но затем я хотел бы извлечь и использовать их. Но я не знаю их точные типы.
Вот код; это немного длинно, но действительно просто:
#include <iostream>
#include <vector>
struct DishBase {
int id;
DishBase(int i) : id(i) {}
};
std::ostream& operator<<(std::ostream& out, const DishBase& d) {
out << d.id;
return out;
}
// Policy-based class:
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase {
Appetizer appetizer_;
Main main_;
Dessert dessert_;
public:
Dish(int id) : DishBase(id) {}
const Appetizer& get_appetizer() { return appetizer_; }
const Main& get_main() { return main_; }
const Dessert& get_dessert() { return dessert_; }
};
struct Storage {
typedef DishBase* value_type;
typedef std::vector<value_type> Container;
typedef Container::const_iterator const_iterator;
Container container;
Storage() {
container.push_back(new Dish<int,double,float>(0));
container.push_back(new Dish<double,int,double>(1));
container.push_back(new Dish<int,int,int>(2));
}
~Storage() {
// delete objects
}
const_iterator begin() { return container.begin(); }
const_iterator end() { return container.end(); }
};
int main() {
Storage s;
for(Storage::const_iterator it = s.begin(); it != s.end(); ++it){
std::cout << **it << std::endl;
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
}
return 0;
}
Хитрая часть здесь, в main()
функция:
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
Как я могу получить доступ к десерту? Я даже не знаю Десертный тип (он является шаблонным), уже не говоря о полном типе объекта, который я получаю от устройства хранения данных.
Это - просто игрушечный пример, но я думаю, что мой код уменьшает до этого. Я был бы точно так же, как для передачи их Dish
классы вокруг, и различные части кода получат доступ к различным частям его (в примере: его закуска, основное блюдо или десерт).
Вам потребуются соответствующие функции-члены для запросов (в данном случае перегрузка для конкретного типа Dessert). Политики должны раскрывать способ обнаружения. Вот краткий пример:
#include <iostream>
using namespace std;
struct TA { virtual string foo() { return "TA::foo\n"; } };
struct DTA : TA { virtual string foo() { return "DTA::foo\n"; } };
template <class T>
struct C {
T t;
};
template <class T>
ostream& operator <<(ostream& o, C<T> c) {
o << c.t.foo();
return o;
}
int main(int argc, char* argv[])
{
C<DTA> c;
cout << c;
}
Насколько я понимаю, классы шаблонов на основе политик не очень дружелюбны к контейнерам. Я просто выбираю простой старый полиморфизм для такого рода вещей. Хотя я был бы заинтересован в решении.
РЕДАКТИРОВАТЬ: Возможно, не случайно я не могу найти какое-либо использование контейнеров stl в книге Александреску «Современный дизайн C ++».
РЕДАКТИРОВАТЬ2: Более подробную информацию о трении между полиморфизмом и универсальностью можно найти здесь http://www.artima.com/cppsource/type_erasure.html . Возможно, ваш контейнер может состоять из boost :: any
объектов?
То, что у вас есть, не совсем основано на политиках дизайн IMO ... если бы это было так, ваш класс должен был бы фактически реализовать (т.е. расширить) политики.
Теперь вернемся к вашему вопросу / примеру. В вашем контейнере вы храните "DishBase *". Верно? С этого момента вы теряете любую информацию времени компиляции относительно фактического типа объектов в коллекции. Так что я боюсь, что то, что вы пытаетесь сделать, невозможно доказать.
Что вы могли бы сделать, так это использовать реальный дизайн на основе политик, например.
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase, Appetizer, Main, Dessert {
}
Затем вы можете просто использовать dynamic_cast для проверки во время выполнения, что вы можете преобразовать свой объект в любую конкретную закуску / десерт / основное блюдо.
Но из вашего описания у меня сложилось впечатление, что вам действительно нужны абстрактные базовые классы (т.е. абстрактные базовые классы могут иметь смысл для вас, а не политики).