Весь смысл наследования как раз и состоит в однократном/редком задании кода алгоритма родителя и добавления вариативности поведения к этому алгоритму путем добавления спец. методов в наследниках, т.н. виртуальных функциях.
И если ты часто переписываешь код родителя, совершенно его так меняя, что приходится и код наследников менять, то это проблема твоего проектирования

В наследнике как раз никогда не нужно переписывать код от родителя, наследник должен уметь пользоваться кодом родителя.
Пример наследования:
Документ - Документ.СчетФактура
В родителе описан метод Записать(), вызывающий Виртуальный метод ВыполнитьЗапись()
1. В Документе код ВыполнитьЗапись() - проверка прав, даты запрета редактирования и т.д. универсальные действия для любых документов
2. В Счет-Фактуре код ВыполнитьЗапись() - вызов родительского ВыполнитьЗапись(), если он возвращает 1, то выполняем спец.действия только для счет-фактуры.
В коде класса Счет-Фактура нет кода для исходного Записать(), есть только ВыполнитьЗапись()
Как видите, никакого дублирования.
И помним, что наследование - это отношения "является", а не содержит.
Возможно, поэтому у вас и код дублируется, и т.п. "плохие запахи"