[БЕЗ_ЗВУКА] Итак, в части I вам нужно было добавить управление слоями карты. Не просто выводить в том порядке, который мы вам сказали, а уметь из json config прочитать нужный порядок слоев и вывести слои именно в таком порядке. Возможно, не выводя какие-то конкретные слои, которые там не указаны. Понятно, что это влияет только на отрисовку карты. Понятно, что функцию main мы уже не меняем. Да, у нас появляется новая настройка отрисовки, это набор слоев, но это все происходит внутри MapRenderer. Мы сразу туда проваливаемся. В MapRenderer, во-первых, конечно, в RenderSettings появляется вектор строк layers, и он простейшим образом парсится из исходного json. И самое интересное теперь, конечно, в методе render у MapRenderer научиться выводить слои в нужном порядке. Как мы это будем делать? Во-первых, конечно, мы неплохо подготовились тем, что все четыре метода вывода — линий автобусов, названий автобусов, кругов остановок и названий остановок — они все имеют одинаковую сигнатуру. А именно, это константные методы MapRenderer, которые возвращают void, то есть ничего, и принимают ссылку на SVG-документ. Это позволит нам сделать словарь с соответствием названия слоя в метод, который соответствует отрисовке этого слоя. То есть если абстрагироваться от того, что у нас C++ и непонятно, как вообще такое сделать, что мы хотим? У нас есть класс MapRenderer, у него есть четыре метода с одинаковой сигнатурой. Мы принимаем из входного json названия слоев. Мы знаем (это же наш код, конечно, мы знаем) соответствие названия слоя конкретному методу, который надо вызвать, чтобы этот слой нарисовать. У нас есть это соответствие. И когда нам нужно нарисовать все слои, мы делаем for по тому самому вектору строк, который нам дали на входе в config с тем, какие слои надо нарисовать, и для каждой очередной строки смотрим, какой метод соответствует этой самой строке. Как это сделать в C++? Можно было сделать как-нибудь. Иначе говоря, накостырить, навелосипедить, как угодно это называйте. То есть написать if'ы в рендренге. If вам ввели в строчку BusLabels, вызвать метод BusLabels, else... if слой BusLines, вызывать метод BusLines. Конечно, это некрасиво, неудобно. Нам нужно по-честному завести словарь из названия слоя в конкретный метод. И вопрос: что такое в C++ этот метод? Вы, наверное, уже сталкивались иногда с тем, что функции в C++ имеют какой-то свой тип. Возможно, кто-то из вас пробовал std::function. И там внутри указывал, опять же, возвращая его значение типа аргументов. Это нечто похожее. Вы можете в C++ завести указатель на функцию, по этому указателю ее вызывать. Так, правда, уже довольно редко делают, потому что есть лямбда-функция, например, для std::function. А здесь мы хотим завести указатель на метод класса. И, соответственно, нам нужен некоторый тип, который будет называться так —указатель на константный метод класса MapRenderer, возвращающий void и принимающий неконстантную ссылку на SVG-document. Такой тип нам нужно уметь объявить. Все, что я говорил последние десять секунд — это все тип. Как его записать? Итак, я в классе MapRenderer создаю статический константный словарь из названия слоя в метод вывода этого слоя. И вот так выглядит этот тип. Он даже уместился в ширину. Что здесь написано? Это указатель на метод класса MapRenderer, который возвращает void и принимает один аргумент типа Svg::Document&, ссылка. Это все здесь написано. По сути, мы взяли заголовок определения метода, убрали все названия (и название метода, и название параметров), и добавили * как знак того, что это указатель. И еще поставили скобки здесь, чтобы там приоритеты с ума не сошли у C++. И все. Это тип указателя на метод данной сигнатуры. Мы его назовем LAYER_ACTIONS. И теперь, во-первых, нужно этот словарь определить. Мы его определяем в map_renderer.cpp. А определяем довольно понятно как. Мы снова пишем const, тип словаря (длинный тип словаря, включающий в себя тип указателя на метод). MapRenderer : : LAYER_ACTIONS= и здесь задаем словарь, где мы указываем ключи в словаре, названия слоев и указатель на метод. Указатель на метод получается очень просто. Тут даже и запоминать ничего не нужно. Адрес (если мы хотим получить указатель, мы должны взять адрес) от метода (MapRenderer : : RenderBusLines). Адрес MapRenderer : : RenderBusLabels. Опять же, указатель на метод не привязан к конкретному объекту, от которого этот метод будет вызываться. Это просто, по сути, адрес в коде программы, где лежит эта самая функция, она же метод. С точки зрения C++ это просто адрес. Поэтому берем адрес такого названия этого метода. Мы создали этот словарь, который мы хотели создать, и осталось только правильно его использовать. Как вызвать полученный здесь указатель на метод от конкретного объекта и от конкретных аргументов? Давайте посмотрим, какой у нас метод render получается. Мы перебираем все слои из render_settings_.layers и вызываем нужный метод, соответствующий тому, что написано в словаре. Давайте внимательно посмотрим на то, что здесь написано. Во-первых, здесь есть совершенно понятная история: это обратиться по конкретному ключу в словаре. Словарь LAYER_ACTIONS, берем ключ layer — это самая строка из набора строк и получаем указатель на метод. А теперь нужно, по сути, вызвать этот указатель на метод от this (от текущего объекта) и от SVG-документа. Как это делается? Мы берем this (тот самый объект, от которого нужно вызвать этот указатель). Пишем стрелочку, потому что this — это указатель. Но не просто стрелочку, на самом деле, а стрелочку со звездочкой. Если вы хотите вызвать не метод, а метод по указателю на этот метод, тогда вы вместо точки пишете точка со звездочкой, а вместо стрелочки пишете стрелочка-звездочка. И с помощью такого оператора из трех символов стрелочка-звездочка, указывая после него указатель на метод, полученный из словаря, вы получаете по сути, сам метод, привязанный к конкретному объекту this. И сразу после этого в круглых скобках вы указываете аргументы для вызова этого метода. Мы, наконец-то, справились — по указателю на метод вызвать этот самый метод. Ровно такой синтаксис. Понятно, что можно было это отсоединить в отдельную переменную. Здесь просто написать метод pointer method_ptr. И среда услужливо выделяла это курсивом до какого-то момента. Итак, вы узнали, как создать в C++ указатель на метод, как выглядит тип этого указателя, как этот указатель получить по методу и как его вызвать. По сути, для части I больше ничего и не нужно.