У меня есть коллекция SceneElements, которые я хочу вывести. Это совокупный класс:
class scene{
public:
vector<sceneElement> elements;
void addElement(sceneElement);
void toStream(std::ostream &);
void fromStream(std::istream &);
};
void scene::addElement(sceneElement e){
elements.insert(elements.end(), e);
}
void scene::toStream(std::ostream &strm){
strm << SCENE_PRE;
int i;
for(i=0; i<elements.size(); i++){
elements[i].toStream(strm);
}
strm << SCENE_POST;
}
это базовый класс:
class sceneElement{
public:
virtual void toStream(std::ostream &);
virtual void fromStream(std::istream &);
};
void sceneElement::toStream(std::ostream &str){
str << "SCENE ELEMENT";
}
void sceneElement::fromStream(std::istream &){
std::cerr << "this is not supposed to be called";
}
и это один из производных классов:
class camera : public sceneElement{
public:
P3d location;
P3d direction;
double fov;
int toString(char**);
virtual void toStream(std::ostream &);
virtual void fromStream(std::istream &);
};
void camera::toStream(std::ostream &strm){
strm << CAMERA_PRE << TAG_LOCATION;
location.toStream(strm);
strm << TAG_DIRECTION;
direction.toStream(strm);
strm << TAG_FOV << fov << CAMERA_POST;
}
но когда я запускаю этот код:
scene sc;
sc.addElement(s);
sc.toStream(cout);
это отображает
<_SCN>SCENE ELEMENT<SCN_>
а не фактический элемент, который он должен был.
Вам нужно хранить указатель на базовый класс в вашем векторе.
В то время как вы думаете, что вы добавили в класс полученные объекты класса, у каждого элемента в векторе достаточно места для объекта базового класса. Таким образом, то, что на самом деле хранится в векторе, это просто часть объекта Base. Производное содержимое класса просто получить отрезанный.
Это явление широко известно как Нарезка объектов в C ++.
Кроме того, вместо хранения сырых указателей в векторе, вы должны рассмотреть возможность использования умных указателей.
Контейнеры STL нельзя использовать полиморфно, потому что их семантика значения и требует однородного размера хранилища.
Каждый производный объект может иметь размер, отличный от размера базового объекта.
В контейнере сложно реализовать простые функции, такие как:
vector<Element> v;
..
int i;
Element e = v [i+5];
если каждый «элемент» между i и i + 5 может иметь разный размер.
Поэтому он просто использует размер статического типа, то есть основы, для каждого элемента.
Способ обойти это ограничение — использовать контейнер указателей. Поскольку все указатели имеют одинаковый размер, независимо от его типа. и мы можем использовать указатели полиморфно.