Search code examples
c++polymorphismvtable

is there anyway to rebuild some saved classes from their vtable?


I'm copying some objects into a file and they all are derieved from same class. but I want to be able to call their functions after loading them to do what that class should do, here's what i did until now:

#include <iostream>
#include <fstream>

using namespace std;

struct a
{
    virtual void print()
    {
        cout << "this is a.\n";
    };
};

struct b : public a
{
    virtual void print()
    {
        cout << "this is b.\n";
    }
};

int main()
{
    ofstream testofile("test.bin",ios::binary);
    a* tempa = new a;
    a* tempb = new b;
    testofile.write((char*)tempa,sizeof(a));
    testofile.write((char*)tempb,sizeof(b));
    testofile.flush();
    testofile.close();
    ifstream testifile("test.bin",ios::binary);
    a* x = (a*)new char[max(sizeof(a),sizeof(b))];
    testifile.read((char*)x,sizeof(a));
    x->print();
    testifile.read((char*)x,sizeof(b));
    x->print();
}

my example works fine but if i comment save part and then run the program it seems the vtable is invalid for the new runed application (though nothing in my code changed). the problem is my file manager class isn't aware of all possible object that may derieve from my base object and I want to rebuild all my application structure using only a single call to file manager to load it. of course each of my objects have their own save/load functions but how should the filemanager guess where is the load function appropriate for the current data chunk?


Solution

  • Please, don't do that. Never.

    Basically, what you do is using a old-style cast to cast a a* to a char*. This results silently in a reinterpret_cast between two unrelated types, and is highly implementation dependant. You cannot rely on the underlying memory layout: it might change for any reason (even when using the same compiler).

    If your class contains pointers, you have no guarantee that the data they point to will still be there (or simply the same) when you reload your class.

    If you want to provide a serialization mechanism, create your own serialize() and deserialize() functions (they can even be templated functions that you can then specialize, or just regular member functions, it doesn't really matter).

    Of course, this requires a bit more work, but for the sake of reliability. Moreover, doing so, you can optimize the data representation to fit any storage type (saved to disk, sent to network, ...) and you can even change your class interface and still keep a compatibility with the already serialized instances.