Сериализация с Cereal для полиморфного класса с использованием виртуального наследования

Я пытаюсь сериализовать и десериализовать полиморфный класс (с виртуальным наследованием), используя Cereal 1.1.2. Я получаю «Нарушение прав доступа — нет данных RTTI!» исключение, когда я пытаюсь передать его производному классу после десериализации. Это прекрасно работает, когда я использую обычное наследование вместо виртуального наследования. Я уже включил RTTI (/ GR) в настройках проекта в Visual Studio 2013 Community Edition. Вот мой код:

class Boogie
{
friend class cereal::access;
virtual void virtualFunction() {}
int boogieInt = 3;
template<class Archive>
void serialize(Archive & archive)
{
archive(boogieInt);
}
};

class Booga : virtual public Boogie
{
friend class cereal::access;
public:
void virtualFunction() {}
int boogaInt = 2;
template<class Archive>
void serialize(Archive & archive)
{
archive(cereal::virtual_base_class<Boogie>(this), boogaInt);
}
};

CEREAL_REGISTER_TYPE(Booga);

int _tmain(int argc, _TCHAR* argv[])
{
try
{
{
std::shared_ptr<Boogie> boogie = std::make_shared<Booga>();
std::ofstream ofs("Booga.txt");
cereal::BinaryOutputArchive archive(ofs);
archive(boogie);
ofs.close();
}

std::shared_ptr<Boogie> deBoogie;
std::ifstream ifs("Booga.txt");
cereal::BinaryInputArchive iarchive(ifs);
iarchive(deBoogie);

std::shared_ptr<Booga> outBooga = std::dynamic_pointer_cast<Booga>(deBoogie);

std::cout << outBooga->boogaInt << std::endl;

std::cin.get();
}
catch (std::exception e)
{
std::cout << "EXCEPTION" << std::endl;
std::cout << e.what() << std::endl;
}
return 0;
}

1

Решение

Ваша проблема в том, что вы сохраняете и загружаете разные типы — ваш код загрузки должен отражать ваш код сохранения.

Также обратите внимание, что вам не нужно использовать виртуальное наследование, поскольку вы наследуетесь только от одного родительского класса — см. Вот для получения дополнительной информации об этом). Кроме того, см. Мой комментарий к вашему сообщению о том, как правильно использовать архивы в RAII-формате.

Ваш вывод может быть указан как:

std::shared_ptr<Boogie> data = std::make_shared<Booga>();
archive( data ); // data is actually a Booga but we hold it in a Boogie ptr

Обратите внимание, что я назначил в Boogie объект, хотя я выделил Booga указатель — это в основном весь смысл полиморфизма, и если вам не нужно это делать, не используйте полиморфизм.

Теперь, когда мы делаем загрузку, мы загружаем в тот же тип, который мы сериализовали:

std::shared_ptr<Boogie> data;
archive( data ); // data is actually a Booga object because of polymorphism

Просто убедитесь, что типы переменных, которые вы фактически передаете в архив, идентичны, независимо от того, чем они на самом деле являются из-за полиморфизма.

0

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