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

Author Topic: Why is sf::Drawable::draw() private?  (Read 5287 times)

0 Members and 1 Guest are viewing this topic.

BZep

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Why is sf::Drawable::draw() private?
« on: December 18, 2014, 01:56:54 pm »
I'm trying to extend the sf::Sprite class with some magic functionality before the derived sf:: Sprite::draw() call, while still allowing the window.draw(drawable) type of call, but it seems almost impossible due to the access modifier on draw() being private and not protected. Of course I could  contain an instance of sf::Sprite within my custom class, but I don't want to forward all calls to this instance.

Generally I've been told that making virtual functions protected and not private is a good code style, as having to call the original function within the derived is often a desired functionality. What is the reasoning behind not doing it here?

~BZep

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Why is sf::Drawable::draw() private?
« Reply #1 on: December 18, 2014, 02:18:22 pm »
I'm trying to extend the sf::Sprite class with some magic functionality before the derived sf:: Sprite::draw() call, while still allowing the window.draw(drawable) type of call.
This is the exact reason why you would derive from a class... I don't know what exactly you want to prevent, but bear in mind that there are non-public access modifiers when inheriting as well...

Generally I've been told that making virtual functions protected and not private is a good code style, as having to call the original function within the derived is often a desired functionality. What is the reasoning behind not doing it here?
It is done here... sf::Drawable::draw() is protected, hence you can call it from a derived class. I don't know why you assume that it is private (probably a misleading compiler error) but it is not. The fact that sf::Sprite overrides the protected function with its own private implementation doesn't prevent you from calling it through the sf::Drawable interface, if you inherit.

What you were told is correct, but I guess you have simply misunderstood it.

You can read more about virtuality here.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

BZep

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Why is sf::Drawable::draw() private?
« Reply #2 on: December 18, 2014, 02:32:11 pm »
Okay holy ****, I spent 2-3 hours struggling with this issue last night without noticing that the original access modifier on Drawable's draw() is indeed protected. I'll toy some more with it when I get home and report back later. :)

BZep

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #3 on: December 19, 2014, 06:06:31 am »
Exactly how do I call the sf::Sprite::draw()?

I have:
class MyClass : public sf::Sprite {
    private:
    void draw(sf::RenderTarget& target, sf::RenderStates states) const {
        // My functionality
        sf::Sprite::draw(target, states); // Yields compiler error due to member being inaccessible
        sf::Drawable::draw(target, states); // Yields linker error
    }
}
 

So how do I do it the correct way? o:

cepro

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #4 on: December 19, 2014, 06:28:09 am »
It would be cleaner to have a class that's Drawable and has a Sprite (composition):
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderStates.hpp>

class MyClass : public sf::Drawable {
    private:
                virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
                        // My functionality
                        target.draw(sprite, states);
                }
   
    private:
                sf::Sprite sprite;
};
 

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #5 on: December 19, 2014, 07:49:30 am »
sf::Sprite::draw is private exactly because we want to prevent users from inheriting from it, as it's generally a bad idea. Can you explain why you want to do that?
Laurent Gomila - SFML developer

BZep

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #6 on: December 19, 2014, 02:48:50 pm »
It would be cleaner to have a class that's Drawable and has a Sprite (composition):

I know and I have tried that. :)
But I wan't my class to behave exactly like an sf::Sprite with a little added functionality, and forwarding all calls to the member is really tedious. I guess I could do some sort of sf::Sprite& getSprite(), but I find the other solution a lot cleaner. :/



sf::Sprite::draw is private exactly because we want to prevent users from inheriting from it, as it's generally a bad idea. Can you explain why you want to do that?

I guess what I want to do is a bit hacky, but it's so much easier than having to call another method do the work before drawing. Basically I just want to do some animation updating in the draw call and then draw the sprite afterwards.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #7 on: December 19, 2014, 03:01:50 pm »
This sounds like one side of the general dilemma of inheritance in OOP languages: Actual inheritance lets you get the base functionality "for free" but lets you potentially break the base class contract (which is why sf::Sprite::draw() is and should be private), while not using inheritance means you have to write all the tedious wrapper functions.

In this case the sf::Sprite interface is not very big, so I'd say do the wrappers.  Maybe you could even use an (evil) macro to make the wrapping process less tedious and verbose.

As an alternative, you could do composition with a sprite and then simply make the sprite public so that you don't need to do all the wrappers.

As another alternative, imo "animation updates" belong in an update() method, separate from the draw() method, so you could simply inherit from sprite, add an update() method, and leave it at that.
« Last Edit: December 19, 2014, 03:03:36 pm by Ixrec »

BZep

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: Why is sf::Drawable::draw() private?
« Reply #8 on: December 19, 2014, 03:48:01 pm »
As another alternative, imo "animation updates" belong in an update() method, separate from the draw() method, so you could simply inherit from sprite, add an update() method, and leave it at that.

I completely agree with this. I'll consider the public sf::Sprite or this solution. Both will have to make me change the source code in my projects that use this, so I think I'll implement it correctly and add the update() method. :)

 

anything