Search code examples
c++inheritanceinterfaceencapsulation

How would you hand a member of a class implementing an interface to another class using the interface?


I was just experimenting with interfaces and wrapping classes and I have come across a roadblock. I am wrapping an SFML::RenderWindow in a class that implements a draw() function. For example:

struct ISprite {
    ....
    functions for sprites...
    ....
}

class SFML_Sprite : public ISprite
{
public:
    ....
    functions implementing stuff for sprites
    ....

private:
    sf::Sprite mSprite;

} 

struct IWindow {
    ...
    virtual void draw(const ISprite& sprite) = 0;
    ...
}

class SFML_Window : public IWindow
{
public:
    ...
    void draw(const ISprite& sprite)
    {
         //This is where the problem is.  Is there a way for me to get to
         //mSprite? 
         mWin.draw(sprite.mSprite);
    }
private:
    sf::RenderWindow mWin;
}

In other words, is there a way for me to pass the underlying stuff around? A pattern I am missing? I am basically trying to hide the windows and sprite implementations. Eventually, I would like to try 'swapping' implementations and go a little lower level, but if I can't figure this out, I am no where near ready to try that.

Thanks!


Solution

  • Why don't you want to do the cast? It's safe and well defined in this context:

    class ISprite {
    };
    
    class SFML_Sprite : public ISprite
    {
    };
    
    class IWindow {
    public:
        virtual void draw(const ISprite& sprite) = 0;
    };
    
    class SFML_Window : public IWindow
    {
    public:
        void draw(const ISprite& _sprite)
        {
           auto sprite = static_cast<const SFML_Sprite&>(_sprite);
        }
    };
    
    int main() {
       SFML_Window i;
       IWindow &a = i;
    
       SFML_Sprite x;
       ISprite &y = x;
    
       a.draw(y);
       return 0;
    }
    

    You can use dynamic_cast if you want to pay for a runtime check to ensure you're really getting the right type, but you always should be as you're not going to be mixing two different graphics backends in the same code.