Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Virtual Inheritance  (Read 23454 times)

0 Members and 1 Guest are viewing this topic.

Imbue

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Virtual Inheritance
« on: November 09, 2008, 03:03:24 am »
Why doesn't SFML use virtual inheritance?

I love SFML's hierarchy and how nested calls to Render() inherit their parents properties. My problem is that I want to expand the Drawable class with logic specific to my game. This works fine for my custom objects, but I can't use multiple inheritance for Sprites, Shapes, or Strings without running into the diamond problem.

Therefor, I currently modify SFML for my use by making Sprite virtually inherit Drawable. I do the same for Shape and String. This will of course impose a small run time performance decrease, but I think that the extra flexibility is well worth it.

As an example, with my current setup I can do:
Code: [Select]

ASprite test; //ASprite inherits from sf::Sprite and includes move functionality.
test.LoadFromFile("sprite.tga")
...
test.AddMove(new Move::LinearA(0, 0, 100, 100, 1.0f));
test.AddMove(new Move::RotateA(0, 90, 1.0f));
That would make test animate from 0, 0 to 100, 100 over the next 1 second while rotating from 0 degrees to 90 degrees. My specific problem is that my ASprite class must know that it's Drawable inorder for the moves to operate on it. Therefor, if it inherits from sf::Sprite, I run into the diamond problem. Virtual inheritance cleanly fixes this. (an alternative is to use dynamic_cast - that has the disadvantage of run time errors)

I was wondering why SFML doesn't do this already, and if you would consider using virtual inheritance in the future.

Thanks!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Virtual Inheritance
« Reply #1 on: November 09, 2008, 10:12:22 am »
I don't use virtual inheritance in the Drawable hierarchy because I don't think it's necessary. I can't imagine a class that would have to inherit from multiple kind of drawables. Even inheriting from a single drawable is often an error, as the "drawable" side of a class is generally just an implementation detail, not a part of its public interface. The only kind of inheritance which makes sense to me is to inherit from sf::Drawable to create a new type of drawable object.

However, I don't see the second inheritance from sf::Drawable in your example. Your class inherits from sf::Sprite, and what else?
Laurent Gomila - SFML developer

Imbue

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Virtual Inheritance
« Reply #2 on: November 09, 2008, 10:40:28 am »
I didn't explain it very well. Let me try again.

I want to make a hybrid Drawable class that does logic and animation as well as all the standard Drawable features. I do something like this:

Code: [Select]
class Animatable : public virtual sf::Drawable
{
   ...
   void AddMove(Move*); //Adds an animation move to our queue.
   virtual void Update(float elapsedTime); //Call once per frame to update logic and do animation.
   ...
};

Since this class applies move objects to itself, it must know that it is a drawable (or use dynamic_cast). The Move class is an abstract base class like:
Code: [Select]
class Move
{
   public:
      virtual void Apply(sf::Drawable& obj, float elapsedTime) = 0;
      virtual void Alive() const = 0; //should return false when the move is over.
};


In general, this works great for me. I can do custom classes like:
Code: [Select]
class Man : public Animatable
{
   ...
   private:
      sf::Sprite head, body, arms, etc;
};

And everything works great. My only trouble is that I'd like to make an animatable sprite:
Code: [Select]
class ASprite : public sf::Sprite, public Animatable //Bam, diamond problem!
{};

If sf::Sprite used virtual inheritance it would circumvent this problem. Currently, I'm modifying it to do just that (it's adding 1 word).

Quote from: "Laurent"
as the "drawable" side of a class is generally just an implementation detail, not a part of its public interface.
But it is a public interface for Sprite, String, and Shape.

Thanks!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Virtual Inheritance
« Reply #3 on: November 09, 2008, 11:13:14 am »
Ok, I see. And I still believe your design is wrong ;)
Your ASprite class should not inherit from sprite, but rather have it as a member. It's an implementation detail of your concept of "ASprite". The way you're doing it rather means you're extending SFML's graphics classes.

Quote
But it is a public interface for Sprite, String, and Shape.

The goal of sf::Drawable is to gather the generic attributes of every graphics object, not to be used as an abstract interface with polymorphism.
And its derived classes (Shape, String, Sprite) are meant for implementing the "visual" side of a class, not for being in turn a base class of something.
Laurent Gomila - SFML developer

Imbue

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Virtual Inheritance
« Reply #4 on: November 09, 2008, 07:21:23 pm »
Quote from: "Laurent"
The way you're doing it rather means you're extending SFML's graphics classes.
That's exactly what I'm trying to do. I want a Sprite, but with extra features like easy animation capabilities.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Virtual Inheritance
« Reply #5 on: November 09, 2008, 07:31:46 pm »
Is Animatable a helper class which is used like other SFML classes, or is it part of a higher level framework that you're writing? Do you send it directly to a sf::RenderWindow, or to a class of yours which wraps it?
Laurent Gomila - SFML developer

Imbue

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Virtual Inheritance
« Reply #6 on: November 09, 2008, 07:46:17 pm »
I guess it's a slightly higher level abstract base class. Since it inherits from Drawable, I do send it directly to RenderWindow.Draw().

The thing is, if I make an ASprite I just want to tell it to move and have it do that. I feel this is much cleaner than making an external loop to update it's position each frame. I feel having it do it automatically repeats less code, is much easier, and divides class responsibility better.

If I'm wrong, or if you have a better way of doing things, please let me know. You're obviously more experienced than I am.

 

anything