Что такое Single и Double Dispatch?

Я написал шаблон посетителя, как следует, но я не понимаю, что такое одиночная и двойная отправка. AFAIK, одиночная отправка – это метод, основанный на типе вызывающего объекта, где двойная отправка вызывает метод, основанный на типе вызывающего и типа аргументов.

Я предполагаю, что двойная отправка происходит в иерархии одного classа, но почему class посетителей имеет две иерархии classов, но по-прежнему считается двойной отправкой.

void floppyDisk::accept(equipmentVisitor* visitor) { visitor->visitFloppyDisk(this); } void processor::accept(equipmentVisitor* visitor) { visitor->visitProcessor(this); } void computer::accept(equipmentVisitor* visitor) { BOOST_FOREACH(equipment* anEquip, cont) { anEquip->accept(visitor); } visitor->visitComputer(this); } void visitFloppyDisk(floppyDisk* ); void visitProcessor(processor* ); void visitComputer(computer* ); 

Пожалуйста, объясните, используя приведенный код.

AFAIK, первая отправка происходит на объекте, который вызывает прием и вторую отправку, происходит на объекте, который вызывает метод посещения.

Благодарю.

Короче говоря, единственная отправка – это когда метод является полиморфным по типу одного параметра (включая неявное this ). Двойная отправка – это polymorphism по двум параметрам.

Типичным примером для первого является стандартный виртуальный метод, который является полиморфным по типу содержащего объекта. А вторая может быть реализована через шаблон посетителя.

[update] Я предполагаю, что в вашем примере floppyDisk , processor и computer каждый наследуют от общего базового classа, который определяет accept как виртуальный метод. Точно так же методы visit* должны быть объявлены виртуальными в equipmentVisitor , который должен иметь некоторые производные classы с различными реализациями visit* . [/Обновить]

Предполагая вышеприведенное, accept полиморфное как на this и на equipmentVisitor . Каждый флоппид, процессор и компьютер имеют свою собственную реализацию accept , поэтому, когда клиент вызывает accept , cal отправляется в зависимости от типа вызываемого абонента. Затем вызывающий абонент обращается к методу посещения конкретного типа посетителя, и этот вызов отправляется на основе фактического типа посетителя.

Теоретически может быть и тройная, четверная и т. Д. Отправка, хотя я никогда не видел, чтобы это реализовано на практике (на языках, которые не поддерживают двойную и более высокую отправку по своей природе, то есть – я, кажется, помню, что Smalltalk делает?). Двойная отправка с использованием Visitor на C ++ и аналогичных языках уже сама по себе ошеломительна, поэтому реализация трех и более высших рассылок будет просто слишком сложной для использования в реальных приложениях.

В вашем примере вам не хватает основ механизма: наследование и виртуальность. Предположим следующую иерархию classов в дополнение к вашему коду:

 class equipmentVisited { virtual void accept(equipmentVisitor* visitor) = 0; } class floppyDisk : public equipmentVisited { virtual void accept(equipmentVisitor* visitor); } class processor : public equipmentVisited { virtual void accept(equipmentVisitor* visitor); } class computer : public equipmentVisited { virtual void accept(equipmentVisitor* visitor); } class equipmentVisitor { virtual void visitFloppyDisk(floppyDisk* ); virtual void visitProcessor(processor* ); virtual void visitComputer(computer* ); } // Some additional classes inheriting from equipmentVisitor would be here 

Теперь представьте, что у вас есть эта часть кода в некоторой функции:

 equipmentVisited* visited; equipmentVisitor* visitor; // ... // Here you initialise visited and visitor in any convenient way // ... visited->accept(visitor); 

Благодаря двойному диспетчерскому механизму, эта последняя линия позволяет любому equipmentVisited быть принятым любым equipmentVisitor , независимо от того, каковы их фактические статические типы. В конце концов, правильная функция будет вызвана для правильного classа.

Чтобы подвести итог:

  • Первая отправка вызывает accept() в соответствующем classе
  • Вторая отправка вызывает соответствующую функцию в classе, выбранном первой отправкой