#ifndef _CPDOCCORE_VISITOR_H_INCLUDED_ #define _CPDOCCORE_VISITOR_H_INCLUDED_ /* Схема работы с visitor: для классов, которые могут быть посещены visitor-ом: 1. наследуем от base_visitable 2. объявляем внутри макрос CPDOCCORE_DEFINE_VISITABLE() class example_visitable_element: public base_visitable { // ... public: CPDOCCORE_DEFINE_VISITABLE(); // ... }; Для создания гостя: 1. наследуем гостя от base_visitor 2. наследуем гостя(визитор) от const_visitor/visitor, const_visitor/visitor, и т.д. для каждого из элементов, котоыре может посетить визитор 3. объявляем для каждого из элементов метод virtual void visit(const visitable_element1& val); virtual void visit(const visitable_element2& val); и т.д. (в случае неконстатности - убираем const) class table_round : public base_visitor, public const_visitor, public const_visitor, public const_visitor { virtual void visit(const office_body& val) { // ... } virtual void visit(const office_spreadsheet& val) { // ... } virtual void visit(const table_table& val) { // ... } }; Для организации обхода: 1. Создаем визитор 2. Выполняем accept для корневого элемента office_element * root; /// ... table_round tableRoundVisitor; root->accept(tableRoundVisitor); Внимание! Визитор САМ определяет правила обхода внутренних вершин, т.е. внутри каждой функции посещения требуется написать например virtual void visit(const office_body& val) { val.content_->accept(*this); } */ namespace cpdoccore { class base_visitor { public: virtual ~base_visitor() {} virtual void on_not_impl(std::string const & message) = 0; }; template class visitor { public: virtual void visit(T&) = 0; // virtual void visit(T const& t) = 0; }; template class const_visitor { public: virtual void visit(T const& t) = 0; }; class base_visitable { public: virtual ~base_visitable() {}; virtual void accept(base_visitor &) = 0; virtual void accept(base_visitor &) const = 0; protected: template static void accept_impl(T& visited, base_visitor & guest) { if (visitor * p = dynamic_cast< visitor * >(&guest)) { return p->visit(visited); } else { guest.on_not_impl(typeid(visited).name()); } } template static void accept_impl(T const& visited, base_visitor & guest) { if (const_visitor * p = dynamic_cast< const_visitor * >(&guest)) { return p->visit(visited); } else { guest.on_not_impl(typeid(visited).name()); } } }; #define CPDOCCORE_DEFINE_VISITABLE() \ virtual void accept(base_visitor& guest)\ {\ return accept_impl(*this, guest);\ }\ virtual void accept(base_visitor& guest) const\ {\ return accept_impl(*this, guest);\ } } #endif