1

When extending a class, is there any difference in performance between polymorphism and composition? Take the following example using composition (in C++):

class Window
{
    public:
        Window(Renderer &renderer) : m_renderer(renderer)
        { }

        void update()
        {
            ....
            m_renderer.draw(this);
        }
    private:
        Renderer &m_renderer;
}

... and using polymorphism:

class Window : public Renderer
{
    public:
        virtual ~Window() {};

        void update()
        {
            ...
            draw();
        }
    protected:
        virtual void draw() = 0;
}

The composition version uses a reference as a member so I suppose that it requires a little more space, but is there any performance gain in either version?

Note: I have checked out similar post such as this, but is does not cover performance.

Thank you for your answers!

Community
  • 1
  • 1
Jens Åkerblom
  • 898
  • 8
  • 19

2 Answers2

5

Well, if you pose the question like this, then yes there is a memory/speed trade-off.

1. Composition

  • 8 bytes (on 64 bits architecture) are likely to be used for the reference

2. Inheritance

  • 8 bytes (on 64 bits architecture) if you need to make your class polymorphic (v-pointer)
  • some overhead for the attributes of the base class if any (note: inheriting from stateful classes is a code smell)
  • ~20% overhead for the virtual call (gross estimate, lots of variation there)

So you might say that inheritance is slightly more costly... but really it's just invisible. The overhead of a function call compared to the inner computation required for graphic rendering is just negligible.


On the other hand, the semantics differ. Whether you inherit or not is significant. Is you Window a Renderer ? Does it make sense ?

Write sane code first. Then optimize as (if !!!) needed.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Inheritance means that the size of the class increasez by at least the size of the base class. It's not only the vftable that adds to the size, but the base class itself. – Luchian Grigore Mar 08 '12 at 13:13
  • @LuchianGrigore: yes, but I have no idea about the size of the `Renderer` class, for all I know it's stateless. Still, worth noting. – Matthieu M. Mar 08 '12 at 13:16
  • Well this size will anyway increase as much... Unless you share Renderer instances between different Windows. – Jens Åkerblom Mar 08 '12 at 13:17
  • @JensÅkerblom not if you use a reference. – Luchian Grigore Mar 08 '12 at 13:18
  • @MatthieuM. a more correct statement would be that it increases by at least 8 bytes, not by 8. It's just misleading. You can't just assume it's stateless. – Luchian Grigore Mar 08 '12 at 13:19
  • @LuchianGrigore: I have distinguished the v-pointer and the attributes so as the make it clear that one cannot be avoided. – Matthieu M. Mar 08 '12 at 13:22
  • @LuchianGrigore The size for composition version = size of window (including reference) + size of renderer. Size of polymorphic version = size of window (no reference) + size of concreate class (= size of renderer). So size difference should be 1 reference right? – Jens Åkerblom Mar 08 '12 at 13:26
  • The semantics can be changed (Renderer -> Renderable) to suit the situation. – Jens Åkerblom Mar 08 '12 at 13:31
  • @JensÅkerblom: That is spelling, not semantics. Semantics is about the meaning of the program. If the `Renderer` object should be shared between instances, then you cannot have each `Window` inherit from it (for example). If multiple classes inherit from `Renderable` then you have polymorphism: is it desired ? useful ? It's a question for you. Only you know what you are trying to achieve. – Matthieu M. Mar 08 '12 at 13:35
4

I suppose you want the second version to be:

class Window : public Renderer

in which case, the memory by inheritance will actually be bigger. That's because, when you inherit something, the class increases in size by at least the sizeof the base class.

The first version actually only suffers a minor increase in size, as you're storing a reference and not an actual object. The following:

class Window
{
    public:
        Window(Renderer &renderer) : m_renderer(renderer)
        { }

        void update()
        {
            ....
            m_renderer.draw(this);
        }
    private:
        Renderer m_renderer; //no reference
}

would take up more space.

More important than anything when deciding between these two is not performance-wise (differences are minor, if at all), but the relationship between the two. Composition and inheritance describe different things.

If a Window is a Renderer, use inheritance. If a Windows has a Renderer, use composition.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625