Страницы

Поиск по вопросам

суббота, 7 декабря 2019 г.

Почему считается, что наследование- это дорогая операция? [закрыт]

#алгоритм #ооп #любой_язык


        
             
                
                    
                        
                            Closed. This question is opinion-based. It is not currently
accepting answers.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Want to improve this question? Update the question so
it can be answered with facts and citations by editing this post.
                        
                        Closed 2 года назад.
                                                                                
           
                
        
Собственно, не раз встречался с фразами вида "Наследование - это дорого и его нужно
избегать.".

Соответственно интересно, с чем это связано (Понятное дело, что истина где-то в ассемблерных
командах после компиляции) и актуально ли это для современных языков и как обстоят
дела в языках с ручным управлением памяти(.NET, Java и т д).

Разве композиция не имеет те же проблемы, так как класс вызывается из класса?
    


Ответы

Ответ 1



Не знаю как в других языках, а в С++ наследование вообще не несет накладных расходов. То есть если не использовать RTTI, то все решается на этапе трансляции и оверхед во время выполнения просто нулевой (в этом и была концепция Страуструпа и огромное спасибо ему за это). Если используются виртуальные методы то оверхед конечно есть, но не больше (или даже меньше), чем если делать ту же функциональность ручками. Чтобы в этом убедиться, достаточно создать пример из классов A и B где B наследник от A с одним или двумя перегруженными виртуальными методами и поглядеть во что разворачивает эту конструкцию транслятор на ассемблере. Благо все современные трансляторы имеют режим вывода в виде ASM листинга. Только надо отключить оптимизацию и вызвать виртуальные функции через указатель на базовый класс, иначе транслятор будет вызывать виртуальные методы не через таблицу виртуальных функций а напрямую, чтобы избежать того самого оверхеда. Кстати, в этом тоже проявляется уменьшение оверхеда - современные трансляторы даже виртуальные методы вызывают напрямую если вызов происходит не по указателю на базовый класс. Если же используется RTTI то там дело сложнее. Оверхед конечно будет, но если использование RTTI оправдано, то оверхед будет опять же меньше, чем если такую же функциональность делать самому. Поглядел другие ответы. В одном из них утверждается, что "Наследование это всегда проверка наличия метода и поиск в родительских классах оного". Для С++ это не так. В С++ вызов виртуальных методов в рантайме происходит через таблицу виртуальных методов без всякого поиска просто по паре индексов и накладные расходы минимальны. Возможно, в каких-то интерпретаторах, которые поддерживают ООП и приходится делать поиск методов, но в компилированном коде после транслятора С++ этого нет. Внутренний голос подсказывает мне, что для точности надо упомянуть не только оверхед по времени исполнения, но и оверхед по памяти. Действительно, для хранения таблицы виртуальных методов в С++ нужна дополнительная память. Но во-первых, в большинстве задач память сейчас дешевле чем скорость. А во-вторых, расход памяти минимальный так как таблица виртуальных методов одна для всех экземпляров класса в программе. И опять же, если такую же функциональность делать самому, то оверхед будет не меньше.

Ответ 2



Собственно, не раз встречался с фразами вида "Наследование- это дорого и его нужно избегать.". Если смотреть с точки зрения производительности относительно процедурного стиля, то ООП это вообще очень дорого. Но надо ли избегать? Это уже смотря что программировать. Для большинства программ, производительности современных компьютеров более чем достаточно. Если смотреть с точки зрения производительности относительно композиции в ооп, то нет не дорого. При композиции, особенно если хорошо соблюдать "Закон Деметры", производительность будет падать сильнее, иногда существенно сильнее, чем при использовании наследования (возникает много-много лишних вызовов методов, как побочный эффект). ПС: Хочу добавить, что при гибкой разработке предпочтение отдаётся композиции перед наследованием. Может быть поэтому его рекомендуют избегать, а не потому, что это "дорого"? ППС: Есть даже методологии, в которых наследование не используется совсем, только композиция.

Ответ 3



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

Комментариев нет:

Отправить комментарий