- •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. Необычный рекуррентный шаблон. Структура, варианты применения.
27. Конструкторы и деструкторы при наследовании. Моменты и порядок вызовов конструкторов. Передача аргументов конструкторам базового класса.
При создании объекта производного класса вызов конструктора базового класса является самой первой инструкцией, опережающей инициализацию любого из членов производного класса и любую инструкцию в программном коде. В то же время, разрушение выполняется с точностью до наоборот.
Такой порядок вызова является очень логичным. При конструировании производный класс, как и его дочерние объекты, могут нуждаться в использовании полей и методов базового класса. Сам производный класс может также нуждаться в собственном дочернем объекте. Соответственно, члены базового класса должны быть инициализированы до того, как они будут использованы, а дочерний объект должен инициализироваться после базового класса, но до выполнения тела конструктора производного класса.
Руководствуясь теми же соображениями, при уничтожении объекта производного сначала выполняется тело его непосредственного деструктора, затем вызывается деструктор дочернего объекта, и, наконец, деструктор базового класса. Данные базового класса, на которые может ссылаться конкретный производный класс, должны существовать в корректном состоянии все время его жизни. Соответственно, вызывать деструктор базового класса безопасно только после завершения деструктора производного класса и его дочерних объектов.
При наследовании конструкторы базового класса не переносятся в производный класс автоматически. Если конструктор базового класса предполагает передачу аргументов, производный класс должен определить свой конструктор, который обеспечит передачу аргументов конструктору базового класса (не обязательно идентичный, лишь бы были переданы все нужные аргументы).
Определять конструктор в производном классе не обязательно только в том случае, если базовый класс имеет конструктор по умолчанию (в таком случае, компилятор просто будет вызывать этот конструктор базового класса).
По этой же причине не обязательно определять собственный деструктор в производном классе, если имеется явный деструктор в базовом. При уничтожении объекта, сгенерированный компилятором по умолчанию деструктор производного класса автоматически вызовет явный деструктор базового класса. Свой деструктор следует определить в производном классе только в том случае, если у него имеются собственные ресурсы, требующие освобождения.
28. Спецификатор доступа protected. Защищенные конструкторы и методы.
Если необходимо запретить создание объектов определенного класса, но в то же время разрешить доступ к его конструктору из производных классов, нужно использовать для решения этой задачи существующий третий спецификатор доступа - protected (защищенный). Члены класса, находящиеся в зоне действия спецификатора доступа protected, являются видимыми для методов этого класса, а также для всех методов классов, производных от него, включая возможное многоуровневое отношения наследования.
Рекомендуется ограничить использование защищенного уровня доступа до реально необходимого минимума. Если принимается решение о помещении члена класса в защищенную область, обычно это имеет реальный практический смысл только для методов, но не для полей. Такие методы могут играть вспомогательную роль для реализации производных классов, когда невозможна эффективная работа производного класса через открытый интерфейс базового, либо когда имеется функциональность, которая не должна быть доступна всем пользователям класса извне, однако пригодится для построения производных классов.
Ниже приведен еще один пример с наследованием классов, использующий защищенные методы. Базовым классом является учетная запись (Account), а производными - покупатель (Customer) и администратор сервера (ServerAdministrator). Базовый класс реализует базовую функциональность авторизации учетной записи на основе проверки пароля, при этом процедуры авторизации нельзя запустить из любого клиентского кода. Авторизацию запускают конкретные классы-наследники, проверяя введенный пароль перед выполнением процедур, действительно требующих авторизации.
Класс Account реализует общие свойства всех учетных записей, включая проверку пароля. Пароль непосредственно не хранится, вместо него используется хэш-код. При авторизации производные классы должны передать в защищенный метод authorize введенный пароль, и если хэш-код от пароля совпадает с образцом, авторизация выполняется успешно.
Если использование защищенных методов может быть вполне оправданным и востребованным, помещение полей базового класса в защищенную область скорее является нарушением инкапсуляции. Если разрешить доступ к полям класса из производных классов, то область программного кода, в которой могут быть нарушены инварианты класса расширяется (пусть и не так мгновенно, как в случае public-полей). Фактически, с защищенными спецификаторами доступа следует быть также аккуратными, как и с отношением дружбы (friend), и применять только в случае реальной необходимости, когда такой шаг существенно облегчает реализацию либо устраняет потери производительности.