18 Мультиметоды и диспетчеризация

      Комментарии к записи 18 Мультиметоды и диспетчеризация отключены

Главная Форумы Программирование Программирование на С++ Заметки о С++ 18 Мультиметоды и диспетчеризация

Помечено: ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 4 мес., 3 нед. назад.

  • Автор
    Сообщения
  • #3596

    Теория

    Для начала напомню, что такое мультиметоды. Посмотрите на приведенный ниже код:

    #include <iostream>
    
    struct shape
    {
        virtual ~shape() {}
    };
    
    struct square   : public shape {};
    struct triangle : public shape {};
    struct sphere   : public shape {};
    
    void foo(shape*, shape*)
    {
        std::cout << "shape*, shape*" << std::endl;
    }
    
    void foo(triangle*, sphere*)
    {
        std::cout << "triangle*, sphere*" << std::endl;
    }
    
    int main()
    {
        shape* s1 = new triangle;
        shape* s2 = new sphere;
    
        foo(s1, s2);
    
        delete s2;
        delete s1;
    
        return 0;
    }

    В данном примере, конечно же, будет вызвана первая функция, так как выбор функции-кандидата происходит на этапе компиляции.

    Мультиметоды можно назвать динамической перегрузкой. Посмотрите на приведенный фрагмент кода. Представьте себе, что вы хотите, чтобы выбор нужной функции, помимо существующих правил, также опирался на информацию о дочерних типах, скрытых за указателями или ссылками на базовые. При этом никаких требований к классам-участникам иерархии быть не должно.

    Сам язык C++ напрямую не предоставляет возможности работать с мультиметодами. Поддержку мультиметодов приходится реализовывать самому, причем ни одного изящного решения этой задачи я пока не видел. Решение так или иначе сводится либо к последовательной проверки указателей-кандидатов через dynamic_cast, либо к составлению RTTI-словарей.

    Code-driven vs data-driven

    Мультиметоды заставляют писать код там, где довольно часто можно воспользоваться данными. Например, современные графические процессоры, позволяющие зрителю любоваться фотореалистичной компьютерной графикой, по большому счету, умеют выполнять только одну операцию — «нарисовать треугольник». У видеокарты нет функций «нарисовать слона» или «нарисовать попугая». У нее есть всего одна функция — «нарисовать треугольник». А кто это будет, слон или попугай, определяется исключительно данными. Точно также у современных систем, рассчитывающих механику взаимодействия тел, нет функции «рассчитать столкновение автомобиля и фонарного столба». Есть всего одна функция — «рассчитать столкновение двух полигональных моделей». Логика работы таких подсистем до тупости проста, и это не случайно. Гораздо проще нарастить производительность железа, нежели сопровождать и развивать сложную динамическую логику обработки данных.

    В итоге

    Являются ли мультиметоды хорошим паттерном или нет — вопрос довольно спорный, и, на мой взгляд, каждый программист должен разрешить его для себя самостоятельно. Что же касается лично меня — я стараюсь избегать их использования.

    Лично я вижу один очевидный случай, в котором необходима диспетчеризация — когда используемое внешнее API вынуждает вас на это. Возможно, что в каких-то особо специфических ситуациях мультиметоды будет оправданным, или даже единственно верным подходом, однако в большинстве случаев, на мой взгляд, существует более легкое и изящное решение.

    Если вы решили использовать наследование — будьте бдительны. Если вы решили использовать мультиметоды — будьте бдительны в квадрате.

Для ответа в этой теме необходимо авторизоваться.