- •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. Необычный рекуррентный шаблон. Структура, варианты применения.
В заголовочный файл не следует помещать элементы реализации модуля, в том числе и внутренние функции, которые необходимы для реализации, однако не существенны для клиентского когда модуля.
Тела функций вместе с необходимыми вспомогательными элементами помещают в файл реализации модуля. Чтобы получить все необходимые определения, файл реализации включает в себя заголовочный файл того же модуля, а также любые другие файлы, необходимые для реализации функций.
Клиентский код также включает заголовочный файл модуля, однако полностью абстрагируется от файла реализации модуля, оперируя функциями модуля как будто встроенными в язык средствами, не обращая внимания на тонкости реализации.
Преимущество модульного разбиения состоит в легкости повторного использования разработанного модуля в другой программе. В случае такой необходимости другой клиентский код может включить заголовочный файл модуля при помощи директивы #include и просто добавить файлы модуля в разрабатываемый проект без копирования. Ниже в виде стрелок представлены зависимости включения между файлами программ. Овалом выделена граница модуля. Файл реализации заполнен другим цветом, поскольку должен логически являться ”черным ящиком” для всех клиентских модулей, при этом интерфейс модуля определяется в открытом заголовочном файле::
При необходимости файл реализации можно полностью скрыть от клиентского кода, предоставляя программам предварительно скомпилированную часть реализации в виде статических (LIB) либо динамически подключаемых (DLL) библиотек. При этом заголовочный файл предоставляется и включается в проект аналогично, а компоновка программы со скомпилированной библиотекой без исходного кода реализации настраивается в свойствах проекта. Например, API операционных систем поставляется именно в таком виде.
Также разбиение задачи на модули способствует упрощению коллективной работы программистов. Двум разработчикам достаточно определить логическую границу модуля в виде структур и объявлений функций в заголовочном файле, а затем один разработчик может заниматься реализацией модуля, а другой - использованием модуля для решения родительской задачи. Часто, по границе модулей проходит разделение между группами разработчиков и даже организациями.
Объектная декомпозиция
Функции и структуры, обрабатывающие понятие последовательности, фактически представляют собой единую целую систему. Структура не имеет особого смысла без обрабатывающих ее функций, а функции теряют элегантность группировки обрабатываемых данных в единые составные переменные. С++ позволяет выразить эту взаимосвязь в более явном виде, разрешая поместить связанные функции внутрь определения структуры.
Функции, определенные внутри структуры, называют ФУНКЦИЯМИ-ЧЛЕНАМИ, или МЕТОДАМИ. В свою очередь, переменные, определенные внутри структуры, называются ПЕРЕМЕННЫМИ-ЧЛЕНАМИ, или ПОЛЯМИ. Поскольку после помещения функций внутрь структуры появляется четко выраженная логическая связь между данными и кодом их обработки, названия следует упростить, убрав из них фрагменты, представляющие собой имя структуры.
Файл реализации видоизменяется следующим образом - перед именами функций ставится имя структуры и оператор разрешения области видимости.
Внутри реализации функции, в частности, после имени объекта-структуры пишется точка, а далее имя функции-члена, аналогично доступу к переменным, являющимся членами структуры. Аналогично видоизменяется тестовый клиентский код.
Если имеется указатель на экземпляр структуру, а не непосредственно переменная структурного типа либо ссылка на нее, то можно использовать синтаксис стрелки.
Следует понимать, что функции-члены не являются частью переменных структурного типа физически, не занимают в них никакой памяти. Помещение функций внутрь определения структуры никаким образом не влияет на представление переменной структурного типа в памяти. Функции связываются лишь логически. Ошибка многих начинающих программистов состоит в заблуждении, что функции-члены физически содержатся внутри объектов-структур. Однако это лишь синтаксическая иллюзия, вызванная использованием операторов доступа к членам . и ->.
С++ полностью устраняет данную избыточность за счет неявной передачи указателя на структуру, на которой вызывается функция-член, в качестве скрытого аргумента. Следует удалить аргумент-структуру из списка аргументов функций, а также не указывать ее при вызове.
Т.е., функция-член на уровне реализации является обычной функцией, содержит имя родительской структуры как часть названия, а также неявно получает адрес объекта, на котором вызывается.
Таким образом, в результате перемещения функций, имеющих логическое отношение к структуре, внутрь самой структуры, получим разбиение программы на взаимодействующие через функции-члены (методы) полнофункциональные объекты, разделенные по модулям. Этот процесс называется объектной декомпозицией.