Короче говоря
они происходят из разных концептуализаций, которые в некоторых языках, где двойная диспетчеризация не поддерживается изначально, приводят к шаблону посетителя как способ объединить две (или более) единичные диспетчеризацию, чтобыиметь суррогатную рассылку.
В длинную
Идея множественной отправки - по сути - разрешить вызов, подобный
void fn(virtual base_a*, virtual base_b*);
(примечание: не как классmember: это НЕ C ++!)
, который можно переопределить как
void fn(virtual derived_a1*, virtual derived_b1*);
void fn(virtual derived_a2*, virtual derived_b1*);
void fn(virtual derived_a1*, virtual derived_b2*);
void fn(virtual derived_a2*, virtual derived_b2*);
, чтобы при вызове
fn(pa, pb)
вызов перенаправлялся на переопределение, котороесоответствует фактическому типу времени выполнения как pa
, так и pb
.(Вы можете обобщить это на любое количество параметров)
В таких языках, как C ++, C #, Java, этот механизм не существует, и диспетчеризация типов во время выполнения в основном работает только с одним параметром (который, будучи одним, выполняется).неявно в функции, делая саму функцию членом класса:
другими словами, псевдокод
void fn(virtual base_a*, base_b*)
становится (реальный C ++)
class base_a
{
public:
virtual void fn(base_b*);
}
Обратите внимание, что здесь нет больше virtual
перед base_b
, который отныне является статическим. Вызов типа
pa->fn(pb)
, если pa указывает на output_a2, а pb на output_b1 будет отправленпроизводная_а2 :: fn (base_b *), независимо от того, есть ли там производный_а2 :: fn (производный_b1 *): тип времени выполнения объекта, на который указывает pb, не учитывается.
Идея паттерна посетителя заключается в том, что вы вызываете виртуальную диспетчеризацию объекта, который вызывает (в конечном итоге обратно) виртуальную диспетчеризацию другого:
class base_a
{
public:
virtual void fn(base_b*)=0;
virtual void on_visit(derived_b1*)=0;
virtual void on_visit(derived_b2*)=0;
};
class base_b
{
public:
virtual void on_call(derived_a1*)=0;
virtual void on_call(derived_a2*)=0;
};
//forward declarations, to allow pointers free use in other decls.
class derived_a1;
class derived_b1;
class derived_a1: public base_a
{
public:
virtual void fn(base_b* pb) { pb->on_call(this); }
virtual void on_visit(derived_b1* p1) { /* useful stuff */ }
...
};
class derived_b1: public base_b
{
public:
virtual void on_call(derived_a1* pa1) { pa1->on_visit(this); }
...
};
сейчас, вызов, подобный pa->fn(pb)
, если pa указывает на output_a1и пб к дerived_b1, наконец, перейдет к derived_a1::on_visit(derived_b1*)
.