2013-06-19 1 views
7

Я видел пару примеров, демонстрирующих шаблон посетителя. Во всех из них каждый вычисленный элемент-элемент реализует то, что обычно называют методом Accept().C++ visitor pattern: Почему каждый полученный посетитель реализует Accept()?

В иерархии цветов, этот метод может выглядеть следующим образом:

void Red::accept(Visitor *v) 
{ 
    v->visit(*this); 
} 

void Blue::accept(Visitor *v) 
{ 
    v->visit(*this); 
} 

Когда посетитель, а также его преемники, есть методы:

visit(Red red); 
visit(Blue blue) 

Мой вопрос, почему не осуществить это таким же образом только в базовом классе (в этом примере: Color), и полиморфизм выполнит эту задачу, а именно, будет вызван правильный визит, поскольку, когда объект является Red, этот динамический тип является Red, поэтому разыменование он даст Red, что, в свою очередь, вызовет визит (красный)?

Что мне не хватает?

+4

Если вы хотите его в базовом классе, тогда вы должны использовать [Любопытно повторяющийся шаблон шаблона] (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern), чтобы получить право 'this'. – user1810087

+0

На более динамичном языке вам, возможно, придется называть функции 'visitBlue' и' visitRed'. Вы можете сделать это и здесь. Помогло ли это в этом смысле? –

+1

Ответ уже предоставлен, но вы можете найти дополнительную информацию в Интернете для «двойной отправки» (я предполагаю, что вы уже искали «шаблон посетителя», и это вам не помогло), что является названием используемой техники Вот. –

ответ

8

Полиморфизм наследования (динамическая отправка) не применяется к аргументам функции. Другими словами, перегруженная функция выбирается из статического типа передаваемых аргументов. Если он реализован в базовом классе Color, то v->visit(*this) всегда будет звонить visit(Color c).

+0

Очистить и направо. То, что заставило меня запутаться, заключается в том, что когда у меня в базе есть не виртуальная функция, и я вызываю из нее виртуальную функцию, полиморфизм будет работать, и виртуальный виртуальный объект будет вызван, если таковой существует. – Subway

+1

Я бы отредактировал его на «не относится к аргументам функции, переданным по значению» (потому что, если вы пройдете по ссылке ** и **, у вас есть правильные виртуальные функции, тогда это применимо) ... – Massa

+1

@ Масса, я верю вы ошибаетесь. Ссылка или нет, это статические типы аргументов, которые используются для выбора, какая перегруженная функция должна быть вызвана. В C++ нет двойной отправки, она только имитируется этим шаблоном посетителя. http://en.wikipedia.org/wiki/Double_dispatch – rectummelancolique

1

Если только accept у вас был ...

void Color::accept(Visitor* v) 
{ 
    v->visit(*this); 
} 

visit просто дозвонились с базовым классом. Чтобы вызвать visit с правильным производным классом, вам понадобится каждый Color, чтобы реализовать его, чтобы они могли правильно набирать this, поэтому вызывается перегрузка visit.

1

Я понимаю, что в методах базового класса указатель this имеет базу типов, а не любых производных классов, поэтому он может обращаться только к методам базового класса и передается как тип Color* this. Когда он передается методу посещения, он попытается запустить visit(Color* color), поскольку полиморфное поведение применяется только к методам самого класса (а не к другим классам).

+0

Что, что, что? –

+0

Когда у меня в базе есть не виртуальная функция, и я вызываю из нее виртуальную функцию, полиморфизм будет работать, и виртуальный виртуальный объект будет вызван, если таковой существует, не так ли? – Subway

+0

Да, но в этом случае он имеет доступ к таблице vtable, которая обрабатывает эту динамическую отправку. Это особый случай, который не применяется к несвязанным классам, используемым в шаблоне посетителя. – Utopia