Производительность при расширении классов, композиция против полиморфизма - PullRequest
1 голос
/ 08 марта 2012

При расширении класса, есть ли разница в производительности между полиморфизмом и композицией? Возьмите следующий пример с использованием композиции (в C ++):

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

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

... и используя полиморфизм:

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

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

Композиционная версия использует ссылку в качестве члена, поэтому я предполагаю, что она требует немного больше места, но есть ли какой-либо выигрыш в производительности в любой версии?

Примечание: я проверил аналогичный пост, такой как this , но это не распространяется на производительность.

Спасибо за ваши ответы!

Ответы [ 2 ]

5 голосов
/ 08 марта 2012

Что ж, если вы зададите такой вопрос, то да есть компромисс между памятью и скоростью.

1.Композиция

  • 8 байтов (на 64-битной архитектуре), вероятно, будет использоваться для ссылки

2.Наследование

  • 8 байт (на 64-битной архитектуре), если вам нужно сделать ваш класс полиморфным (v-указатель)
  • некоторые издержки для атрибутов базового класса, еслилюбой (примечание: наследование от классов с состоянием - это запах кода)
  • ~ 20% накладных расходов для виртуального вызова (общая оценка, много изменений)

Таким образом, вы можете сказать, чтонаследование немного дороже ... но на самом деле это просто невидимо.Затраты на вызов функции по сравнению с внутренними вычислениями, необходимые для рендеринга графики, пренебрежимо малы.


С другой стороны, семантика отличается.Являетесь ли вы наследником или нет, это важно.Вы Window a Renderer?Имеет ли это смысл?

Сначала напишите вменяемый код.Затем оптимизируйте как (если !!!) нужно.

4 голосов
/ 08 марта 2012

Полагаю, вы хотите, чтобы вторая версия была:

class Window : public Renderer

, в этом случае память по наследству будет на самом деле больше.Это потому, что когда вы наследуете что-то, класс увеличивается в размере как минимум на sizeof базовый класс.

Первая версия на самом деле страдает лишь незначительным увеличением размера, так как вы сохраняете ссылку ине фактический объект.Следующее:

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

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

будет занимать больше места.

Более важно , чем что-либо другое, когда выбор между этими двумя значениями не влияет на производительность (различия незначительны, еслина всех), но отношения между двумя.Состав и наследование описывают разные вещи.

Если Window является Renderer, используйте наследование.Если Windows имеет Renderer, используйте композицию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...