views:

119

answers:

2

Hello!

I have run into trouble trying to implement functionality for serializing some classes in my game. I store some data in a raw text file and I want to be able to save and load to/from it. The details of this, however, are irrelevant. The problem is that I am trying to make each object that is interesting for the save file to be able to serialize itself. For this I have defined an interface ISerializable, with purely virtual declarations of operator<< and operator>>.

The class Hierarchy looks something like this

              -> GameObject -> Character -> Player ...
ISerializable               -> Item -> Container ...
              -> Room ...

This means there are many possible situations for serializing the objects of the different classes. Containers, for instance, should call operator<< on all contained items.

Now, since operator>> is virtual, i figured if I wanted to serialize something that implements the functionality defined in ISerializable i could just do something like

ostream & Player::operator<<(ostream & os){
    Character::operator<<(os);
    os << player_specific_property 1 << " " 
       << player_specific_property 2 << "...";
    return os;
}

and then

ostream & Character::operator<<(ostream & os){
    GameObject::operator<<(os);
    os << character_specific_property 1 << " " 
       << character_specific_property 2 << "...";
    return os;
}

but I quickly learnt that this first attempt was illegal. What I'm asking here is how do I work around this?

I don't feel like implementing a function manually for each class. I guess I'm looking for something like the super functionality from Java.

Any help is appreciated.

-- COMMENTS ON EDIT ------------

Alright, last time I was in a hurry when I was writing the question. The code is now more like it was when I tried to compile it. I fixed the question and the problem I had was unrelated to the question asked. I'm ashamed to say it was caused by an error in the wake of a large refactoring of the code, and the fact that the operator was not implemented in every base class.

Many thanks for the replies however!

+4  A: 

The problem is not in your attempt to call a virtual function non-virtually. The problem is this line: os = Character::operator<<(os);. That is an assignment, but std::ostream doesn't have an operator=.

You don't need the assignment anyway. The stream returned is the same stream as the stream you pass in. The only reason it's returned is so you can chain them.

Hence the fix is to just change the code to

ostream & Player::operator<<(ostream & os){
    Character::operator<<(os);
    os << player_specific_property 1 << " " 
       << player_specific_property 2 << "...";
    return os;
}
MSalters
Matthieu M.
Entirely true, but I only fixed the compile problem, not the conceptual one, From the edited question it is now clear that the root cause was really a loss of insight.
MSalters
+3  A: 

This is not how overloading operator<< for ostream works. The left-hand operator is an ostream (hence you gotta overload it as a free function) and the right-hand operator is your object (which is why the virtual mechanism wouldn't easily work.

I suppose you could try:

class Base
{
    //...
    virtual std::ostream& output(std::ostream&) const;
};

std::ostream& operator<< (std::ostream& os, const Base& obj)
{
    return obj.output(os);
}

Now a derived class naturally might call the output method of its parent(s):

class Derived: public Base
    //...
    virtual std::ostream& output(std::ostream& os) const
    {
        Base::output(os);
        return os << my_specific_data;
    }
};
UncleBens