Виртуальные функции, не выполняющие версии производных классов

У меня есть коллекция 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_>

а не фактический элемент, который он должен был.

1

Решение

Вам нужно хранить указатель на базовый класс в вашем векторе.
В то время как вы думаете, что вы добавили в класс полученные объекты класса, у каждого элемента в векторе достаточно места для объекта базового класса. Таким образом, то, что на самом деле хранится в векторе, это просто часть объекта Base. Производное содержимое класса просто получить отрезанный.
Это явление широко известно как Нарезка объектов в C ++.

Кроме того, вместо хранения сырых указателей в векторе, вы должны рассмотреть возможность использования умных указателей.

2

Другие решения

Контейнеры STL нельзя использовать полиморфно, потому что их семантика значения и требует однородного размера хранилища.

Каждый производный объект может иметь размер, отличный от размера базового объекта.

В контейнере сложно реализовать простые функции, такие как:

vector<Element> v;
..
int i;
Element e = v [i+5];

если каждый «элемент» между i и i + 5 может иметь разный размер.

Поэтому он просто использует размер статического типа, то есть основы, для каждого элемента.

Способ обойти это ограничение — использовать контейнер указателей. Поскольку все указатели имеют одинаковый размер, независимо от его типа. и мы можем использовать указатели полиморфно.

1

По вопросам рекламы [email protected]