Как шаблон посетителя избежать удручения - PullRequest
11 голосов
/ 15 июля 2010

Может ли кто-нибудь показать пример кода до и после, чтобы избежать приведения кода шаблона посетителя вниз?

Спасибо.

Ответы [ 2 ]

21 голосов
/ 15 июля 2010

Простой минималистичный пример.

До

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

// Some arbitrary function that handles Base.
void
Handle(Base& obj) {
    if (...type is Derived1...) {
        Derived1& d1 = static_cast<Derived1&>(base);
        std::printf("Handling Derived1\n");
    }
    else if (...type is Derived2...) {
        Derived2& d2 = static_cast<Derived2&>(base);
        std::printf("Handling Derived2\n");
    }
}

Это означает, что Base должно иметь поле типа, или вы будете использовать dynamic_cast для проверки каждого типа.

После * * 1 010 // Class definitions class Visitor; class Base { public: // This is for dispatching on Base's concrete type. virtual void Accept(Visitor& v) = 0; }; class Derived1 : public Base { public: // Any derived class that wants to participate in double dispatch // with visitor needs to override this function. virtual void Accept(Visitor& v); }; class Derived2 : public Base { public: virtual void Accept(Visitor& v); }; class Visitor { public: // These are for dispatching on visitor's type. virtual void Visit(Derived1& d1) = 0; virtual void Visit(Derived2& d2) = 0; }; // Implementation. void Derived1::Accept(Visitor& v) { v.Visit(*this); // Calls Derived1 overload on visitor } void Derived2::Accept(Visitor& v) { v.Visit(*this); // Calls Derived2 overload on visitor } Это была основа. Теперь вы реализуете фактического посетителя для полиморфной обработки объекта. // Implementing custom visitor class Printer : public Visitor { virtual void Visit(Derived1& d1) { std::printf("Handling Derived1\n"); } virtual void Visit(Derived2& d2) { std::printf("Handling Derived2\n"); } }; // Some arbitrary function that handles Base. void Handle(Base& obj) { Printer p; obj.Accept(p); } Accept() - это виртуальная функция, отправляющая тип obj (первая отправка) Затем вызывается соответствующая перегрузка Visit(), потому что внутри Accept() вы уже знаете тип вашего объекта. Visit(), в свою очередь, представляет собой виртуальную функцию, которая отправляет информацию о типе посетителя (вторая отправка). Поскольку у вас двойная отправка (одна на объект, другая на посетителя), вы не выполняете кастинг. Недостатком является то, что каждый раз, когда вы добавляете класс в вашу иерархию, вы должны идти и обновлять свой класс посетителя, чтобы добавить соответствующую функцию для обработки нового подкласса.

4 голосов
/ 15 июля 2010

В примере wikipedia используется двойная рассылка, без даункинга.

...