Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 969
Ali1S232 Avatar asked Feb 23 '23 19:02

Ali1S232


2 Answers

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.

like image 164
ereOn Avatar answered Feb 26 '23 10:02

ereOn


The code your are writing will not be portable (endianess).

As an exemple virtual function table offset of a base class or struct may change. Solaris and Aix compiler put the vft at end of struct/class and the VC++ at the offset(0) in case of single inheritence. I never check with g++ but some fun is possible.

I do not recommend direct write of object unless you have a bulk and you do not have to maintain these data for a long time (ie. temporary data).

The value of the vft depends where you dynamic library (dll or so) is mapped in virtual memory. If you write you own allocator and patch the vft it may work. But it is quite slimmy.

like image 32
VGE Avatar answered Feb 26 '23 10:02

VGE