Většině diskutujících uniká je, že dědičnost v jazycích jako Java, C++ apod. representuje vlastně 3 koncepty. Je to dědění dat (většinou nechci, porušuje zapouzdření, lepší je použít skládání), dědění chování (většinou nechci, vede k fragile base class a porušuje zapouzdření), definice rozhraní(většinou chci, pomáhá k využití polymorfismu, pomáhá strukturovat kód - neprogramuju proti implementaci). Interface je dokonce často oddělen od dědičnosti - Java, C#.
Podle mě OOP jazyk vůbec nemusí umožňovat dědit data a chování a přesto se v tom bude dobře programovat bez duplikování kódu. Protože často ani "is a" neznamená, že je správné použít dědění ve smyslu dědění chování nebo dat a jde mi jen o interface. Každý asi zažil šílené hierarchie dědění, kde pomalu každá metoda volá nejdřív implementaci předka nebo kvanta protected atributů, co se ve většině tříd nikdy nepoužijí nebo se přes ně předávají argumenty funkce, ale ani jedno nejde rychle opravit bez rozbití poloviny systému.
IMHO podle mě pro objektové programování je nejdůležitější programovat proti rozhraní, dodržovat zapouzdření a každá třída musí mít jenom jednu roli (signle responsibility). Pokud tohle dodržuju, dědičnost (nepočítám implementaci interface) mi z programu z velké části zmizí a spíš slouží k modelování dat než k deduplikaci kódu.