Теперь смотри - 0 функций, остальные тоже уходят в цппшки каждого класса(по сути - нормализация твоего кода):
#include <iostream> using namespace std; struct Warrior; struct Troll; struct WarriorVisitor { void visit(Warrior* warrior); }; struct TrollVisitor { void visit( Troll* troll); }; struct CreatureVisitor : public virtual WarriorVisitor, public virtual TrollVisitor { using WarriorVisitor::visit; using TrollVisitor::visit; }; struct Creature { virtual void accept( CreatureVisitor* visitor) = 0; }; struct Warrior : public Creature { virtual void accept( CreatureVisitor* visitor) { visitor->visit( this); } }; struct Troll : public Creature { virtual void accept( CreatureVisitor* visitor) { visitor->visit( this); } }; void WarriorVisitor::visit( Warrior* warrior) { cout << "Warrior visitor" << endl; } void TrollVisitor::visit( Troll* troll) { cout << "Troll visitor" << endl; } int main( ) { CreatureVisitor visitor; Creature* cr = new Warrior; Creature* tr = new Troll; cr->accept( &visitor); tr->accept( &visitor); delete tr; delete cr; return 0; }
Уже лучше, в правильном направлении идем.
Усложняем задачу.
Теперь я хочу иметь несколько визиторов.
У тебя же CreatureVisitor знает про WarriorVisitor, TrollVisitor - и если применить мою магию то и еще об 100500 Warrior.
Толстый класс.
А я знаю что все 100500 тысяч наследованы от простого Warrior
И я хочу зделать визитор который обслужит только всех Warrior и все.
Отдельно хочу зделать второй визитор который обслужит только Troll
в твоем случаее это без кодо-оверхеда нельзя
Просто не переопределяй метод accept у класса Troll : public Warrior и он обслужится как воин.
Используй базовые визиторы по отдельности.
Или я что-то недопонимаю?
Стоп, кажись понял :)
Ну тут да, ты прав. Но по моему небольшой кодо-оверхед лучше чем небольшой скорость-оверхед.
И ты не ответил что делать с ошибками каста:)
bazhenovc
Ну вот видишь, мы пришли к класической проблематике программирования "CPU, Memory, Development Time"
Напомни, что за ошибки каста?
IROV..
Если ты случайно передашь туда мусор и каст вернёт 0
bazhenovc
Динамик каст вернет 0 и....??
if( TVisitor * p = dynamic_cast<TVisitor*>(_visitor) ) { p->visit(_impl); }
тогда мы не войдем в этот if и пойдем дальше.
А что тебя смущает?
IROV..
И? Exception?
смотри есть dynamic_cast не сработает (типы разные) то он вернет NULL
тут стоит проверка если не NULL
правильней переписать вот так
TVisitor * p = dynamic_cast<TVisitor*>(_visitor)
if( p != NULL )
{
p->visit(_impl);
}
если ноль, мы заканчиваем обработку для этого обьекта.
IROV..
Я имею в виду твои действия:) Если визитор должен делать что-то важное, то он просто тупо не отработает? Или ты как-то про это информировать будешь (например исключением)?
По моему втихую скипать объект как то не очень правильно. Надо будет руками добавлять обработку ошибок, а это в свою очередь повысит общую сложность проекта что в свою очередь будет приводить к новым ошибкам.
Хотя можно написать пару лишних строк и оставить проверку типов компилятору, что в свою очередь ещё и быстрее:)
bazhenovc
На самом деле, "втихую скипать объект" это правильно ;)
IROV..
Видимо у нас разные взгляды на жизнь:)
решил собрать свой велосипед ради интереса.
class CMyRender; class CMyRender2; class CWidget; struct SVisitorTable { typedef void (CMyRender::* const FRENDER )( CWidget* pWidget) ; typedef void ( CMyRender2::* const FRENDER2 )( CWidget* pWidget) ; FRENDER pRenderVisitor; FRENDER2 pRender2Visitor; }; template<typename BASE> class CVisitorMap { protected: inline CVisitorMap( ); private: static SVisitorTable _table; }; template<typename TYPEVISITOR,typename TYPE, typename FUNCT> struct SVisitorMap { static FUNCT _funct; }; class CTable { public: inline CTable( ); const SVisitorTable* _pVisitorTable; }; inline CTable::CTable( ): _pVisitorTable( NULL) { }; template<typename BASE> inline CVisitorMap<BASE>::CVisitorMap( ) { static_cast<CTable*>( static_cast<BASE*>( this) )->_pVisitorTable = &_table; }; template<typename BASE> SVisitorTable CVisitorMap<BASE>::_table = { SVisitorMap<CMyRender,BASE,SVisitorTable::FRENDER >::_funct , SVisitorMap<CMyRender2,BASE,SVisitorTable::FRENDER2 >::_funct };
class CWidget: public CTable, private CVisitorMap<CWidget> { //ля ля ля }; class CxWidget: public CWidget, private CVisitorMap<CxWidget> { };
class CMyRender { public: inline void render(CWidget* pWidget) { ( this->*( pWidget->_pVisitorTable->pRenderVisitor))( pWidget); } public: void renderWidget( CWidget* pWidget) { printf( "renderWidget\n"); } void renderxWidget( CWidget* pWidget) { CxWidget* pxWidget = static_cast<CxWidget*>( pWidget); printf( "renderxWidget\n"); } }; SVisitorTable::FRENDER SVisitorMap<CMyRender,CWidget, SVisitorTable::FRENDER >::_funct = &CMyRender::renderWidget; SVisitorTable::FRENDER SVisitorMap<CMyRender,CxWidget, SVisitorTable::FRENDER >::_funct = &CMyRender::renderxWidget; //----------------------------------------------------------------------- class CMyRender2 { public: inline void render( CWidget* pWidget) { ( this->*( pWidget->_pVisitorTable->pRender2Visitor))( pWidget); } public: void renderWidget( CWidget* pWidget) { printf( "render2Widget\n"); } void renderxWidget( CWidget* pWidget) { CxWidget* pxWidget = static_cast<CxWidget*>( pWidget); printf( "render2xWidget\n"); } }; SVisitorTable::FRENDER2 SVisitorMap<CMyRender2,CWidget, SVisitorTable::FRENDER2 >::_funct = &CMyRender2::renderWidget; SVisitorTable::FRENDER2 SVisitorMap<CMyRender2,CxWidget, SVisitorTable::FRENDER2 >::_funct = &CMyRender2::renderxWidget;
CMyRender myRender; CMyRender2 myRender2; CWidget w; CxWidget xw; myRender.render(&xw); myRender.render( &w); myRender2.render( &xw); myRender2.render( &w);
Пока писал.. мотерился. вот почему нельзя сделать статические виртуальные функции и переменные. по идее что тут набросал это простые статические виртуальные применены pRenderVisitor, pRender2Visitor. +учитывая что статик уже существует до создание объекта то ими можно пользоваться в базовых объектов.
>>susageP
Срань господня
Тема в архиве.