Steve Dewhurst "C++ Common Knowledge"

Побывал на тренинге Steve Dewhurst‘а “C++ Common Knowledge”. У меня уже давно есть его книга:

и в целом конкретно этот тренинг посвящен темам из нее.

Очень прикольный дядька. Нескучно, разбавлено подколами аудитории и шутками типа что ребята из Boost’a не иначе как курят шаблоны и т.д. Мне очень понравилось.

Стив сказал, что С++ - это практически все, что делал и делает в жизни. Писал компиляторы, утилиты, разбирался в стандартах, а сейчас вот дает тренинги.

Не могу сказать, что я узнал что-то особенно новое — это было бы странно, так как его книжку (см. выше) читал от корки до корки и периодически к ней возвращаюсь. Хотя, пожалуй, одна мысль меня зацепила: правильное написание конструктора копирования или оператора присваивания для класса, в иерархии которого есть виртуальный базовый класс с данными является весьма запутанной задачей. Тут однозначно нарушается принцип логической независимости уровней иерархии наследования, так как надо точно знать, от каких классов ты унаследован и как их правильно инициализировать при множественном наследовании.

Рекомендация такая: сначала задаешь себе вопрос: а нужно ли мне тут множественное наследование? а нужно ли мне виртуальное множественное наследование?? а нужно ли мне виртуальное множественное наследование с данными в базовом виртуальном классе??? И даже после долгого раздумья лучше сказать “нет”. Лично я не имею ничего против множественного наследования. Но мне не очень нравится как это сделано в С++. И мне не очень нравится как это сделано в Java. Мне очень нравится, как сделано в Go. А именно: в Go полностью разнесены понятия структур данных и интерфейсов. Структуры данных не могут быть унаследованы. Они могут только реализовывать интерфейсы. А наследовать можно только интерфейсы. Поэтому в принципе нельзя при наследовании подцепить чужие данные, а только методы. А нет данных, не и проблемы их инициализации.

Итак, могу просто собрать общие рекомендации от Стива:

  • стараться использовать виртуальные функции и полиморфизм в целом вместо if и case
  • стараться использовать алгоритмы STL/Boost и функторы вместо циклов
  • использовать только “умные” указатели при работе с динамической памятью
  • не использовать классические массивы, а контейнеры STL (так как, например, std::vector гарантирует линейное размещение элементов, то можно смешивать “старый” код, работающий с указателями, с использованием контейнеров)
  • тщательно продумывать операции копирования сложных классов (лучше всего реализовать конструктор копирования и метод swap, а оператор присваивания реализовать через них)
  • всегда объявлять в коде класса конструктор копирования и оператор присваивания, и даже если они не используются, то просто закомментировать их объявление с пояснением, почему они не нужны
  • никогда не использовать приведения типов в стиле С, только С++ (static_cast, const_cast и т.д.), так как они длинные, их нудно набивать и они уродуют вид программы - в общем, все, что нужно для минимизации их наличия
  • помнить, что наследование - это re-use интерфейсов, а не кода как такового
  • не слишком верить компилятору ;-) (Стив их писал и знает, что они могут и подставить)

Оригинальный пост | Disclaimer

Комментарии