Что именно случилось, что нам нужна двойная диспетчеризация / посетитель в с ++ - PullRequest
2 голосов
/ 27 сентября 2019

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

Например, этот код:

#include <iostream>

class A {
public:
};
class B : public A {
};

class F {
public:
    virtual inline void operator()(const A&) const noexcept {
        std::cout << "FxA" << std::endl;
    }
    virtual inline void operator()(const B&) const noexcept {
        std::cout << "FxB" << std::endl;
    }
};

class G : public F {
public:
    virtual inline void operator()(const A&) const noexcept {
        std::cout << "GxA" << std::endl;
    }
    virtual inline void operator()(const B&) const noexcept {
        std::cout << "GxB" << std::endl;
    }
};

void by_const_ref(const F& f, const A& a) {
    f(a);
}

int main() {
    by_const_ref(F(), A());
    by_const_ref(F(), B());
    by_const_ref(G(), A());
    by_const_ref(G(), B());

    return 0;
}

Без двойной отправки второй и четвертый вызов by_const_ref не преобразует B () в объект A.

Из этой статьи: https://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C++ Я понимаю, что этовключает в себя искажение имени и время компиляции, а также разрешение vtable во время выполнения, но я не нашел, как именно.

Что касается обработки имени, я посмотрел на скомпилированный объект, но не нашел ничего особенного.

Для vtable я сбросил его с помощью g ++ -fdump-lang-class, и, похоже, там тоже не было много информации.

Отсюда мой запрос.Я хотел бы понять, что именно произошло, и, возможно, как проверить это поведение (используя такие инструменты, как nm, проверка vtable, машинный код?)

1 Ответ

3 голосов
/ 27 сентября 2019

Вы пошли слишком глубоко, это намного проще.

Виртуальные функции C ++ включают динамическую диспетчеризацию на основе типа одного параметра, this.Двойная диспетчеризация, как следует из названия, является динамической диспетчеризацией, основанной на типе двух параметров.Поскольку язык не предоставляет эту функцию, шаблон Visitor просто использует встроенную одиночную диспетчеризацию дважды, используя каждый динамический параметр как this по очереди.

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

...