Сайт Билла Стивенса представляет собой сборник ответов на частые вопросы по стилю и техникам написания C++. Автор предупреждает, что эта страница обновляется редко, поэтому стоит следить за новым FAQ на isocpp.org или изучать C++ Core Guidelines для современных правил.
В начале статьи разбирают типичную задачу: прочитать несколько чисел, обработать их и вывести результат. Для этого используют стандартный вектор vector из пространства имен std. Вектор динамически расширяется, а при выходе из области видимости освобождает память, поэтому ручной new/delete здесь не нужен. Если ввод завершается символом конца файла (Ctrl-D на Unix), цикл прерывается. Если нужно завершить ввод словом "end" вместо EOF, стоит очистить ошибку потока перед чтением строки-терминатора. Важно помнить, что файл должен иметь расширение .cpp, иначе компилятор может обработать его как C-код. Имена функций и классов пишутся по-английски, например main, Shape, Circle, без транслитерации.
При описании иерархии наследования автор обращает внимание на проблему хрупких базовых классов. Если в базовом классе Shape хранить общие данные в защищённых (protected) членах, изменения реализации будут вызывать перекомпиляцию клиентского кода. Решение — делать интерфейсы чистыми (abstract), объявляя чистые виртуальные функции через = 0. Если общие данные действительно нужны всем потомкам, выносят их в отдельный микс-класс.
Разбирают также тонкости работы с пустыми базовыми классами и оптимизацию размера объекта. Виртуальный деструктор обязателен в базовом классе, если есть хоть одна виртуальная функция, чтобы корректно освобождать ресурсы у объектов-потомков, уничтожаемых через указатель на базу. Нельзя вызывать виртуальные функции внутри конструкторов, так как механизм виртуализации отключён до полного завершения инициализации. Деструкторы работают наоборот: базовая часть уничтожается последней.
Для создания объектов через полиморфизм используют фабричные паттерны с виртуальными конструкторами, что позволяет изолировать логику создания конкретных типов. Чистые виртуальные функции требуют переопределения во всех потомках или делают класс абстрактным. Перегрузка функций работает только внутри одного класса; чтобы подключить перегрузки из базы к потомку, используют using-директивы.
Автор обсужрует контейнеры из <vector>, <list>, <map> и <unordered_map>. Рекомендуют избегать void* и писать код на уровне абстракции, используя стандартные типы контейнеров. Для хранения объектов разных типов в однородном контейнере подходят умные указатели или интерфейсные абстракции. Оптимизировать контейнеры стоит только если есть реальные измерения производительности, а не теоретические страхи. std::vector обычно быстрее ручальных списков благодаря кэш-локальности.
В заключение автор напоминает, что стандартная библиотека предоставляет статически типизированные и эффективные инструменты, которые нужно использовать в большинстве случаев.