Search code examples
c++filebinarytypenametypeid

Save a Type to a file


Im trying to make a level loading system, where the level file is stored as some binary file that has the class of the object to be spawned and its position and scale. One thing I cant figure out is how to convert a class type into something that can be written to a binary file and also retrieved later.

I tried converting it to a string, but then how do I turn that typeid(type).name() back into the class type to spawn?

Open to any methods of doing this


Solution

  • There are a few things going on here, so I took the liberty of writing a short snippet.

    In order to read in a bunch of objects into a single container like the below when you don't know their type, they all need to derive from a base class. Alternatively you could pass the deserialize function different vectors (or other containers) to store the different types. Whatever works.

    The deserialize function then uses a switch like @darune suggested to construct the appropriate type.

    There are all sorts of serializing / deserializing libraries out there which will allow you to be more sophisticated than this and store more complex groups of objects. I often use rapidjson for this sort of thing. boost.serialize is another option (again as @darune suggested).

    #include <fstream>
    #include <iostream>
    #include <vector>
    
    using std::ifstream;
    using std::vector;
    using std::cout;
    using std::endl;
    
    class Object
    {
    public:
        double position;
        double scale;
    
        Object(const double& position, const double& scale)
        : position(position), scale(scale) { }
    
        virtual ~Object() {}
    };
    
    class Foo : public Object
    {
    public:
        static const int id = 0;
        Foo(const double& position, const double& scale)
        : Object(position, scale) { }
    
    };
    
    class Bar : public Object
    {
    public:
        static const int id = 1;
        Bar(const double& position, const double& scale)
        : Object(position, scale) { }
    };
    
    Object* deserialize(int id, const double& position, const double& scale)
    {
        switch (id)
        {
            case Foo::id:
                return new Foo(position, scale);
            case Bar::id:
                return new Bar(position, scale);
            default:
                return nullptr;
        };
    }
    

    And then an example of reading in from a text file looks like

    int main(void)
    {
        vector<Object*> objects;
    
        ifstream fin;
        fin.open("objects.txt");
        if (!fin)
            throw std::runtime_error("Unable to open file");
    
    
        // Read in the id, position and scale from a file
        int id;
        double position, scale;
    
        while (!fin.eof())
        {
            fin >> id >> position >> scale;
            Object* object = deserialize(id, position, scale);
            if (object != nullptr)
                objects.push_back(object);
        }
    
        fin.close();
    
        // Print out the objects
        for (auto pobj: objects)
            cout << pobj->position << " " << pobj->scale << endl;
    
        // Don't forget to clean up
        for (auto object: objects)
            delete object;
    }
    

    In this case objects.txt was a text file that is just whitespace delimited id position scale (with no header). For example

    1 0.4 10
    0 0.1 5
    0 0.1 1
    

    Reading in from binary is similar.