- •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. Необычный рекуррентный шаблон. Структура, варианты применения.
31. Реализация виртуальных функций. Указатель vptr и таблица vtable. Вызов виртуальной функции. Инициализация служебных данных для работы виртуальных функций в конструкторах.
В начало каждого объекта полиморфного класса помещается неявный указатель VPTR (virtual functions table pointer) на соответствующую таблицу виртуальных функций. При чем для всех объектов одного и того же конкретного класса этот указатель указывает на одну и ту же таблицу виртуальных функций. Например, в начале двух объектов-файлов будут одинаковые указатели VPTR на одну и ту же таблицу VTABLE для класса File:

В свою очередь, два объекта-директории будут иметь аналогичные указатели VPTR на таблицу виртуальных функций своего класса Directory:

Фактическое значение указателя VPTR неявно устанавливается в конструкторе
объекта. Конструктор каждого класса самостоятельно отвечает за установку значения данного указателя на нужную таблицу. В момент, пока управление не вышло из конструктора базового класса в конструктор производного, значение указателя vptr пока не соответствует таблице конкретного класса, а используется таблица базового класса.
Как только управление переходит в конструктор дочернего класса, указатель переключается на другую таблицу:
- фрагмент дизассемблированного кода конструктора базового класса:
; Установка указателя vptr на таблицу виртуальных функций класса FilesystemEntry
008B1225 mov dword ptr [eax],offset FilesystemEntry::`vftable' (8C6338h)
- фрагмент дизассемблированного кода конструктора производного класса:
; Вызов конструктора базового класса
00054689 call FilesystemEntry::FilesystemEntry (516D1h)
0005468E mov dword ptr [ebp-4],0
00054695 mov eax,dword ptr [ebp-14h]
; Установка указателя vptr на таблицу виртуальных функций класса Directory
00054698 mov dword ptr [eax],offset Directory::`vftable' (74978h)
pRootDir->show( std::cout, 0 );
; Передача аргументов для функции (заталкиваются в сегмент стека в обратном порядке)
00A0C999 push 0
00A0C99B mov eax,dword ptr [__imp_std::cout (0A1D364h)]
00A0C9A0 push eax
; В регистр ecx записывается адрес объекта - указателя на базовый класс (pRootDir)
00A0C9A1 mov ecx,dword ptr [ebp-18h]
; В регистр edx из объекта извлекается адрес таблицы виртуальных функций
00A0C9A4 mov edx,dword ptr [ecx]
; В регистр eax записывается адрес функции со смещением от начала таблицы на 8 байт.
; На 32-битной платформе это соответствует строчке таблицы с порядковым номером №2
00A0C9A9 mov eax,dword ptr [edx+8]
; Осуществляется вызов функции через извлеченный адрес
00A0C9AC call eax
32. Контроль переопределения виртуальных функций. Требования к сигнатурам. Ключевые слова override и final. Ковариантность возвращаемых типов.
Переопределение виртуальных функций из базовых классов в производных осуществляется на основе сопоставления сигнатур:
● названия виртуального метода;
● количества и типов аргументов;
● модификатора const на методе (влияет на неявный указатель this);
● возвращаемого типа.
Если хотя бы один из этих компонентов сигнатуры не совпадает между базовым и производным классом, функция не считается переопределенной.
Очевидно, если не совпадают названия, нет никакой возможности сопоставить функции.
Если название совпадает, но отличается количество, типы аргументов либо модификатор const - функция в производном классе интерпретируется не как переопределенная, а как перегруженная. Соответственно, замещения функции базового класса не произойдет, а якобы переопределенные функции просто станут новыми виртуальными функциями из-за несовпадения сигнатур (пример листинга программы сюда кидать не буду)
Такие ошибки чаще возникают не сразу, а при последующей модификации кода, когда в базовый класс вносится изменение в сигнатурах виртуальных методов, а в производном сделать аналогичные изменения забывают. Во избежание подобных ошибок, в новом стандарте языка С++’11 добавлено специальное ключевое слово override для выражения более явного намерения переопределить виртуальную функцию из базового класса. Встретив такое ключевое слово, компилятор проверяет действительно ли в базовых классах существует виртуальная функция с совместимой сигнатурой. Если такая функция фактически не обнаруживается, компилятор генерирует ошибку.
Кроме того, в С++’11 было также предложено ключевое слово final, запрещающее дальнейшее переопределение виртуальных функций в производных классах. Такое поведение может потребоваться авторам библиотек, которые считают разумным запретить дальнейшее наследование и переопределение виртуальных методов иерархии как нелогичное:
Ковариантность(covariance) - когда возвращаемый тип в переопределяемом методе производного класса является производным от возвращаемого типа в методе базового класса. Например, для иерархии объектов файловой системы можно представить некоторую виртуальную функцию для “клонирования”, создающую точную копию объекта, имея указатель или ссылку на базовый класс. Должна создаваться полная копия, учитывая возможные дочерние элементы директорий
Такой метод может быть переопределен с ковариантным возвращаемым типом .
За счет ковариантного возвращаемого типа стало возможным получение более точного объекта-результата без необходимости небезопасного преобразования типа вниз по иерархии.
