🔒 Locked
Files, Memory and Objects Lists
Advertisement
Original Post
I posted this question a while ago, but I didn''t pharse it right or something so here it goes.
Say I have a list of IObjects, and I need to be able to save them to file and load them again. So IObject has two virtual members, IWrite, IRead, or whatever. The problem is not howto read to and from file, or where ever they exist it is how do I know which object to create when I''m reading from file. If the list contains pointers to different types of objects how do I know which object to create.
Say the list contains two objects.
CBall, and CPaddle; everyone loves pong
lol
and the functions are:
CBall::Write(some_stream ss)
{
ball.x outToSomeStream(ss);
ball.y outToSomeStream(ss);
}
ect..
Basicly should I give each object a tag and then dynamic cast each to find out what type of object, save the tag and the data. THen when I read it I can have a big switch statment to create the objects of the right type.
There must be a better way. Ie: without the switch, and dynamic_cast, so all I have to do is define the virtual functions in each overloaded function.
Any ideas??
Thanks,
Nick
Müsli Games
www.musli.tk
Write the actual class name before its data, then use reflection to determine the type when reading in.
E.g.
CBall::Write(some_stream ss)
{
"CBall" outToSomeStream(ss);
ball.x outToSomeStream(ss);
ball.y outToSomeStream(ss);
}
(Unfortunately I can''t help you with the other side of the equation since I only know reflection for Java.
)
E.g.
CBall::Write(some_stream ss)
{
"CBall" outToSomeStream(ss);
ball.x outToSomeStream(ss);
ball.y outToSomeStream(ss);
}
(Unfortunately I can''t help you with the other side of the equation since I only know reflection for Java.
What is reflection? Another minor problem is I use the same function to read in and out. But I could fix that. Even if I write out the actual class name how do I know which class to call to read the data back in. Should I give a return type to indicate whether or not the object could be read in?
Thanks so far,
Nick
Müsli Games
www.musli.tk
Thanks so far,
Nick
Müsli Games
www.musli.tk
I looked up abstract factory and it helps a little but doesn''t really do much more than my first solution. Type fields ect.. Every time I want to add a class I dont'' want to have to add a type field and a switch statment to my file in/out method. But I see no other way right now. Any ideas? Or how do you save, read objects when you don''t know what the pointer actually points to.(not saving it but saving it so I can open it)
Nick Merritt
Thanks,
Nick Merritt
Thanks,
Yeah, RTTI is already being used so I might as well use it so more. If I compile my program on a different complier I will have to re-build all my levels and files won''t I?
Thanks, I think it solves my problem.
Nick
Müsli Games
www.musli.tk
Thanks, I think it solves my problem.
Nick
Müsli Games
www.musli.tk
I don''t think you''re going to find the solution you were hoping for... You''re gonna just end up with the switch...
The good news is that if you use inhertance correctly (IE, push most members up to base classes), you can get a lot of re-use out of you''re serialization code...
Tony
The good news is that if you use inhertance correctly (IE, push most members up to base classes), you can get a lot of re-use out of you''re serialization code...
Tony
Using typeids I can get out of using type fields defined by me. However I''ll still have to check how they are named and make a switch for each object won''t I? I wish C++ had a better way of doing this!!!
Nick
Nick
I had a similar problem before with a messy switch statement that I somewhat cleared up using a lookup table of function pointers. Basicly the structure had 2 members, item_type and a pointer to the function I wanted to use to load that type of item. In my object manager class I had a member function for loading each type of object (yeah, I know, yuck, but the readability is very good compared to a switch statement). At any rate, each function only consisted of creating a new object of the correct class, calling it''s own virtual object.load(etc) member and returning a pointer to the base class. If you keep the items in the lookup table sorted correctly, you can do something similar to (minus some hard to remember function pointer syntax) object = function_table[item_type].function( stream/or whatever ) or just loop through the table to match up the type (by using a lable like you mentioned) to a function. Unfortunately this doesn''t save you much in the way of typing out code, but IMO it is just much easier to manage than a huge switch statement and much easier to read.
Evillive2
E-Mail
Evillive2
E-Mail
After a bit of playing around, I''ve managed to get C++ to do persistence of lists without using any switch statements.
The key thing is to use templates, and use RTTI, it seems that it is possible to write a template function which gets the typeid of its template parameter.
Then you can make an array (constant, defined at compiletime), of template loader functions for all the different objects. Then loop through the array until one of them succeeds. It will create an object of the appropriate type (using new), if the parameter is the same as the typeid().name of the class it''s templated for.
This does actually seem to work, and I think it would be a sensible approach for savegame files, which do not need to be portable between different instances of the game.
But for leveldata, it''s not a good idea, as the RTTI names are possibly going to vary depending on the compiler and other factors, so they aren''t guaranteed to be the same for each build of the game (say you switch to a different compiler, or modify your source somewhat). And cross-platform compatibility (of data) is totally out of the window.
Obviously persisting references (i.e. pointers) contained within your object list, is another issue. I guess you could give each object a unique ID at save time, and store that, then fix the pointers back up at load time. But it''s messy.
(Standard example: user saves a game while a homing missile is locked on the bad guys, it needs to remember which bad guy it''s locked on)
Mark
The key thing is to use templates, and use RTTI, it seems that it is possible to write a template function which gets the typeid of its template parameter.
Then you can make an array (constant, defined at compiletime), of template loader functions for all the different objects. Then loop through the array until one of them succeeds. It will create an object of the appropriate type (using new), if the parameter is the same as the typeid().name of the class it''s templated for.
This does actually seem to work, and I think it would be a sensible approach for savegame files, which do not need to be portable between different instances of the game.
But for leveldata, it''s not a good idea, as the RTTI names are possibly going to vary depending on the compiler and other factors, so they aren''t guaranteed to be the same for each build of the game (say you switch to a different compiler, or modify your source somewhat). And cross-platform compatibility (of data) is totally out of the window.
Obviously persisting references (i.e. pointers) contained within your object list, is another issue. I guess you could give each object a unique ID at save time, and store that, then fix the pointers back up at load time. But it''s messy.
(Standard example: user saves a game while a homing missile is locked on the bad guys, it needs to remember which bad guy it''s locked on)
Mark
Yeah, I''m not quite sure how, evillive2 solution is any better. I''m using that strategy for collisions and I find it really messy but it is a neat idea. Maybe it is just the way i''m doing it. Any ways, I coded a little demo that works fine. Basicly any object that can be saved inherits, IStorable, which contains two methodes, VInOut(ISerielizer *I) and VGetObjectType() which returns a std::string of the object type. Then for a switch statment, each object has a static methode call StaticGetObjectType() which returns the same string. I use this for comparing each object, that way there isn''t two strings to update, ie: one in the switch(actually it is a if, else if)s and one in the object. Works quite well, and I''ll think i''ll stick with it because it works and not all the time every thing needs to know how to save everything. Ie: most structures are rather static and know what they contain.
markr:
Yeah, that was one of my major concerns, because I loading level data. Visual C++, says it doesn''t even ensure that the typeid is the same from one build to the next. Strings arn''t that bad, besides then I can read them. lol
Yeah, pointers are a problem, I haven''t really thought to much about yet. I was just thinking of using the id strategy. I haven''t thought of much difference.
Thanks, for everyone''s help.
Nick
Müsli Games
www.musli.tk
markr:
Yeah, that was one of my major concerns, because I loading level data. Visual C++, says it doesn''t even ensure that the typeid is the same from one build to the next. Strings arn''t that bad, besides then I can read them. lol
Yeah, pointers are a problem, I haven''t really thought to much about yet. I was just thinking of using the id strategy. I haven''t thought of much difference.
Thanks, for everyone''s help.
Nick
Müsli Games
www.musli.tk
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement