- •1. Абстракция и декомпозиция. Основные виды декомпозиции программ.
- •Модульная декомпозиция
- •В заголовочный файл не следует помещать элементы реализации модуля, в том числе и внутренние функции, которые необходимы для реализации, однако не существенны для клиентского когда модуля.
- •Объектная декомпозиция
- •2. Понятие класса и объекта. Переменные-члены и функции-члены. Обращение к членам класса через объект. Указатель this. Константные функции-члены.
- •3. Спецификаторы доступа. Понятие инкапсуляции. Отличие конструкций class и struct. Методы доступа.
- •4. Конструкторы классов, синтаксис, разновидности, моменты вызова конструкторов. Роль конструкторов в соблюдении инвариантов классов.
- •5. Конструкторы по умолчанию (default constructors). Тривиальные и нетривиальные сгенерированные конструкторы классов. Конструирование массивов объектов.
- •6. Списки инициализации. Синтаксис, отличие от присвоений в теле конструктора, необходимость в существовании.
- •7. Деструкторы классов, синтаксис, цель, моменты вызова деструкторов.
- •8. Моменты копирования объектов. Поведение по умолчанию. Конструктор копий и оператор копирующего присвоения.
- •9. Временные объекты. Явные и неявные конструкторы. Оптимизации rvo/nrvo. Временные объекты
- •Неявные и явные конструкторы
- •Запрещение копирования
- •Оптимизация копирования
- •10. Основные отличия между классами-значениями и классами-сущностями. Запрещение копирования объектов. Основные отличия между классами-значениями и классами-сущностями.
- •11. Перемещение объектов. Конструктор перемещения и оператор перемещающего присвоения. Понятие rvalue-ссылки. Функция std::move.
- •12. Перегрузка операторов. Оправданное и неоправданное использование. Пример перегрузки простейшего оператора. Операторы, которые нельзя перегружать.
- •13. Внутриклассовые и глобальные перегруженные операторы. Перегрузка операторов сдвига. Применение перегрузки сдвига для взаимодействия с потоками ввода/вывода.
- •14. Перегрузка операторов сравнения и арифметических операторов. Основные правила реализации и применения.
- •15. Перегрузка операторов индексной выборки, префиксного и постфиксного инкремента/декремента. Перегрузка операторов преобразования типа.
- •16. Статические переменные-члены. Цель применения. Синтаксис. Особенности компоновки.
- •17. Статические функции-члены. Синтаксис, особенности применения. Фабричный метод. Статические функции-члены
- •Фабричный метод
- •19. Физическое и логическое постоянство объектов. Модификатор mutable.
- •20. Класс std::string из стандартной библиотеки. Основная функциональность, способы применения. Особенности внутренней структуры.
- •21. Композиция объектов. Иерархии целое-часть. Структура простейшей композиции по значению в памяти. Ответственность за уничтожение объектов при композиции.
- •22. Ссылочная композиция. Разрываемая композиция. Кратность композиции. Одиночная, множественная и недетерминированная кратность.
- •23. Применение контейнера std::vector для композиции с недетерминированной кратностью. Композиция объектов-значений и объектов-сущностей.
- •24. Композиция объектов с кратностью многие-ко-многим. Основные особенности объектных отношений, способы реализации.
- •25. Наследование классов. Необходимость в отношении наследования. Структура наследования в памяти. Повышающее преобразование типа.
- •26. Критерии оценки корректности применения наследования. Примеры корректного и некорректного применения наследования.
- •27. Конструкторы и деструкторы при наследовании. Моменты и порядок вызовов конструкторов. Передача аргументов конструкторам базового класса.
- •28. Спецификатор доступа protected. Защищенные конструкторы и методы.
- •29. Понижающее преобразование типа (downcast). Опасности. Поля идентификации типов.
- •30. Виртуальные функции. Полиморфизм. Цель. Синтаксис, примеры использования.
- •31. Реализация виртуальных функций. Указатель vptr и таблица vtable. Вызов виртуальной функции. Инициализация служебных данных для работы виртуальных функций в конструкторах.
- •32. Контроль переопределения виртуальных функций. Требования к сигнатурам. Ключевые слова override и final. Ковариантность возвращаемых типов.
- •33. Чисто виртуальные функции и абстрактные классы. Вызов чисто виртуальной функции в конструкторе до завершения инициализации объекта.
- •34. Понятие интерфейса. Применение интерфейсов.
- •35. Множественное наследование конкретных классов. Синтаксис, структура в памяти, особенности применения и реализации.
- •36. Преобразование типов при множественном наследовании в верхнем и нижнем направлениях. Коррекция указателя this.
- •37. Множественное наследование классов с повторяющимся базовым. Синтаксис, структура в памяти, особенности применения и реализации.
- •38. Виртуальные базовые классы. Синтаксис, структура в памяти, особенности применения и реализации. Понятие “самого производного” класса и его роль в организации работы виртуальных базовых классов.
- •39. Механизм rtti - назначение, особенности применения. Структура std::type_info, оператор typeid для выражений и типов.
- •40. Применение оператора dynamic_cast для указателей и ссылок. Основные цели использования. Отличия от операторов static_cast, reinterpret_cast и const_cast.
- •41. Альтернативные решения, заменяющие dynamic_cast. Виртуальные функции для понижающего преобразования. Типовое решение Visitor.
- •42. Обработка исключений. Цели, синтаксис выброса и обработчиков. Выбор обработчика по типу. Передача данных исключения по значению, указателю и ссылке. Исключения языка и стандартной библиотеки.
- •44. Шаблоны функций и классов. Синтаксис определения шаблонов. Инстанцирование шаблонов. Модель включения и явное инстанцирование.
- •Шаблоны классов
- •45. Аргументы шаблонов - типы, константы, шаблонные аргументы шаблонов. Дедукция фактических аргументов шаблонов.
- •46. Понятие обобщенной концепции. Статический полиморфизм по сравнению с динамическим полиморфизмом.
- •Статический полиморфизм
- •47. Итераторы stl - основные разновидности, итераторы контейнеров, итераторы, не связанные с контейнерами.
- •48. Классификация алгоритмов стандартной библиотеки. Примеры применения наиболее часто используемых алгоритмов.
- •49. Функциональные объекты stl. Простые функциональные объекты. Стандартные функциональные объекты. Связыватели std::bind.
- •50. Понятие лямбда-выражения. Синтаксис, особенности использования. Реализация лямбда-выражений компилятором. Список захвата лямбда-выражения.
- •51. Специализация шаблонов. Полная и частичная специализация. Статический выбор вариантов на основе специализации шаблонов.
- •52. Необычный рекуррентный шаблон. Структура, варианты применения.
29. Понижающее преобразование типа (downcast). Опасности. Поля идентификации типов.
При написании программного кода манипулирующего средствами из базовых классов может возникнуть необходимость в различной обработке объектов в зависимости от их конкретного типа. Предположим, имеется набор транспортных средств, и требуется подсчитать их общий приблизительный вес вместе с перевозимым грузом / пассажирами при максимальной загрузке. Собственный вес является характеристикой любого транспортного средства (имеется метод getWeight в классе Vehicle), однако перевозимый вес оценивается по разным правилам для автобусов и грузовиков. Максимальный вес перевозимого содержимого грузовика известен при его конструировании. А вес пассажиров можно оценить умножением количества пассажирских мест на некоторый условно выбираемый средний вес человека (согласно данным из открытой энциклопедии, средний вес человека на планете оценивается в 62кг).
Имея набор указателей на объекты базового класса не существует простого способа отличить их конкретный тип. Чтобы реализовать описанный алгоритм подсчета суммарного веса в первом варианте введем в базовый класс Vehicle специальное дополнительное идентифицирующее поле перечисляемого типа (m_type), по которому автобусы можно будет отличить от грузовиков не имея указателя на конкретный объект
Производные классы должны скорректировать свои конструкторы, передавая конкретное значение идентифицирующего поля.
При определении веса конкретного транспортного средства следует определить его тип, а затем сделать ПОНИЖАЮЩЕЕпреобразование типа (downcast, движемся вниз по иерархии классов), чтобы извлечь необходимые для подсчета данные из производных классов.
Опасности: Понижающее преобразование типа вниз по иерархии наследования никак не проверяется во время выполнения и, в общем случае, чревато ошибками. При таком преобразовании программист должен быть абсолютно уверен, что объект имеет тот самый тип (либо производный от него), к которому осуществляется такое преобразование.
Это замечание является наиболее серьезным из всех. В принципе, в этом конкретном примере это правило обеспечено логикой конструирования объектов. В общем же случае, если объект реально имеет другой тип, преобразование вниз по иерархии приведет к неправильной интерпретации содержимого памяти. Предположим, происходит преобразование типа вниз к типу Truck, а на самом деле объект относится к типу Bus.
Опасность ситуации состоит в том, что неправильное преобразование довольно трудно обнаружить. Достаточно часто никаких ярких видимых дефектов не проявляется. Обнаружить некорректность преобразования можно намного позже, получив неожиданный результат при дальнейшем вызове методов.
30. Виртуальные функции. Полиморфизм. Цель. Синтаксис, примеры использования.
ВИРТУАЛЬНЫХ ФУНКЦИЙ (virtual functions). Такая особая форма функций,
будучи введенной в базовом классе и помеченной ключевым словом virtual, может быть замещена, или переопределена (overridden), другой реализацией с идентичной сигнатурой в производном классе. А в момент вызова виртуальной функции через указатель или ссылку на базовый класс будет использоваться реализация, соответствующая фактическому типу объекта.
ПОЛИМОРФНЫМ (polymorphism = много форм). Виртуальные функции функционируют таким образом, что при вызове через указатель или ссылку на базовый класс управление попадает в версию функции, соответствующую типу вызываемого объекта, известному в момент его создания. Полиморфизм является одним из трех фундаментальных принципов в объектно-ориентированном программировании,
Отметим преимущества использования такого подхода:
основной реализуемый алгоритм не заботится ни о преобразовании типа вниз по иерархии, ни о полноте рассмотрения всех возможных объектов - используется единый интерфейс, предполагая, что объект обеспечит корректное поведение, соответствующее своему классу;
при расширении иерархии новыми классами код алгоритма менять не нужно - вместо этого новый класс должен предоставить собственное переопределение виртуальной функции, и тогда он удовлетворит ожидания всех имеющихся использований иерархии.
class Vehicle
{
public:
virtual float getMaxExtraWeight () const { return 0.0f; }
};