Diamond Inheritance Workaround

Started by
6 comments, last by Aface 17 years, 10 months ago
Hi All, Im having a problem in the game im working on that im pretty sure is what people describe as the dreaded diamond inheritance problem. I have a "Streamable" abstract base class which most classes in my game inherit from. It provides an interface for serializing a class. It also implements a function to make a hash check of the derived object as all the hash check does is save the object to memory instead of file, and then do a crc32 check on the serialized data in memory. Now i have several classes that inherit from streamable - namely GameObject (a base class for all objects in the game that includes map location etc), and Damageable (all objects that can be damaged inherit from this class which include current damage level and fires off events when the object is destroyed etc). Lastly i have a physical game object - say a Ship which derives from both GameObject and Damageable. Everything works fine for all the pure virtual funtions of Streamable, but the implemented function GetDataHash gives a compiler "Ambiguous" error which i can understand. I understand i can workaround by making the Streamable version virtual, and specifying the base class in each derived class (ie ship), but is there a better programming style / design pattern i can use to overcome having to make an entry in each derived class specifying the getdatahash() which all have the same code? Sorry for the long description. Alex
Advertisement
You need to look into something called virtual inheritance.

Example:
class Base {
  public:
    virtual void Do() = 0;
};

class Der1 : public virtual Base {
  public:
    virtual void Do() {}
};

class Der2 : public virtual Base {
  public:
    virtual void Do() {}
};

class Fin : public Der1, public Der2 {
  public:
    virtual void Do() {}
};


int main() {
  Base *b = new Fin();
b->Do();
}


What this does is ensure that you have only one copy of Base in a derived class, when that class indirectly derives from the base several times.

Please do make sure you read the above link, it's invaluable.


jfl.
Virtual inheritance should solve your issue, but let's reflect on your design for a while. Are there Damageables that aren't GameObjects? If so, what are those? If not, certainly Damageable should "be-a" GameObject - that is, the hierarchy should be a simple

Streamable <- GameObject <- Damageable <- Ship etc.

You might also want to consider composition instead of inheritance - the former tends to allow more flexibility in design and use than the latter.
Quote:Original post by Sharlin
Virtual inheritance should solve your issue, but let's reflect on your design for a while. Are there Damageables that aren't GameObjects? If so, what are those? If not, certainly Damageable should "be-a" GameObject - that is, the hierarchy should be a simple

Streamable <- GameObject <- Damageable <- Ship etc.

You might also want to consider composition instead of inheritance - the former tends to allow more flexibility in design and use than the latter.

I do agree with that, just so we're clear.
Hi Guys,

Thanks for the replies - i must not have explained myself very well.

Here is a code example of what i have as the base streamable class

class Streamable
{
public:

//virtual save / load interfaces to be implemented by derived classes
virtual void Save(CFile* fs)=0;
virtual void Load(CFile* fs)=0;

//implemented function - this is always the same in derived classes
DWORD GetHash(){FileInMemory file; this->Save(file); CRC32(file);}

};

Each derived class (ie gameobject and damageable) implement the Save / Load functions and that is all fine.

The problem comes when i create a class Ship which derives from both gameobject, and damageable - i get a compiler error about the ambiguous use of GetHash() - which is fair enough because it doesnt know whether to use Gameobjects inherited version, or damageable's. I can work around this by making gethash virtual, and writing the exact same code as in the base class, but this seems like a messy workaround.

Alex

P.S. - Sharlin - yes, i have thought about using composition, but I dont think it fits in my situation - there are some places (ie the editor) where i would want a damageable object, that wasnt a gameobject.

[Edited by - Aface on June 8, 2006 9:14:23 PM]
Yes, as we said, virtual inheritance is the solution. The following compiles nicely:

class Base {  public:    void Do() { }};class Der1 : public virtual Base {};class Der2 : public virtual Base {};class Fin : public Der1, public Der2 {};int main() {  Fin fin();  fin.Do();}
Then I'm not sure what you mean. How are you trying to use GetHash()? Can you give the exact error message?

[edit] Oh, wait, I think I get it. You can unambiguate such situations with a using statement:
class Fin : public Der1, public Der2 {
  public:
    virtual void Do() {}
    using Der1::GetHash;
};

Nontheless, using virtual inheritance would also solve this problem.
Are you re-implementing GetHash in GameObject and Damageable?
[/edit]

[edit2] OK, I'll try again. Virtual inheritance will solve this problem too. Again, read the article I linked to.
Quote:Thanks for the replies - i must not have explained myself very well.


I was wrong. Not a little wrong. Very wrong. Both of you have answered my questions completely. Thanks to both of you - ratings++.

Alex

This topic is closed to new replies.

Advertisement