Хороший пост, я бы по сути примерно то же самое сказал, но не так хорошо как Анатолий :)
Мой опыт за последние 7-8 лет подтверждает основные пункты:
• ООП это круто главным образом как инструмент для модуляризации.
• Инкапсуляция это круто.
• Наследование интерфейсов это круто. (Наследование от абстрактного класса, или полиформизм над абстрактными функциями, как реализация интерфейса).
• Наследование кода это не круто, ведёт к багам и тяжело сопровождать. Основная проблема – программист, глядящий в потомка, должен мочь полностью абстрагироваться от предка, а, на самом деле, не может, и вынужден делать какие-то предположения о том, как предок работает. Эти предположения часто не правильны.
• Множественное наследование это ужасно, ведёт к тяжёлым багам.
Добавлю ещё от себя, что:
• Агрегация (где возможно и уместно) зачастую лучше наследования. Легче тестировать, лучше модульность.
• Один параметризованный класс-предок лучше иерархии с кучей классов, наследующих и немножко меняющих предка.
• Нужно иметь опыт, чтобы получать бенефиты от ООП. Скажем, проблемы от overuse ООП (куча ненужных wrapper’ов, уровней абстракции и др.overengineering’а) зачастую более серьёзны (wrong assumptions, abstraction leaks, complexity), чем сложности от сопровождения если тупо фигачить модули в сишном стиле. Другими словами, неопытный программист, хорошо знающий ООП, более опасен, чем неопытный программист, его не знающий. По-моему, ООП это очень важно и нужно, но я бы, наверное, не был против если бы стоял вопрос о том, чтобы не давать его на первом курсе.
Темплейты это тоже некруто. Они убивают читаемость, особенно при отладке, и это сводит на нет плюсы от недублирования кода. Кроме того, за исключением очень редких случаев каких-то хардкорных библиотек (скажем, самое ядро движка сложной 3D игры), реальные задачи не требуют универсальности типов данных и пр. Матрица тестирования всё равно сильно увеличивается, и создаётся кажущаяся иллюзия, будто бы её можно не увеличивать, отсюда новые баги.