Архитектура движка.Форум

Паттерны GoF - Visitor + bonus Acyclic Visitor (лекция) (комментарии) (3 стр)

Страницы: 1 2 3
#30
14:26, 28 мар 2011

Теперь смотри - 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;
}
#31
14:45, 28 мар 2011

Уже лучше, в правильном направлении идем.

Усложняем задачу.

Теперь я хочу иметь несколько визиторов.

У тебя же CreatureVisitor знает про WarriorVisitor, TrollVisitor - и если применить мою магию то и еще об 100500 Warrior.
Толстый класс.

А я знаю что все 100500 тысяч наследованы от простого Warrior
И я хочу зделать визитор который обслужит только всех Warrior и все.
Отдельно хочу зделать второй визитор который обслужит только Troll

в твоем случаее это без кодо-оверхеда нельзя

#32
14:57, 28 мар 2011

Просто не переопределяй метод accept у класса Troll : public Warrior и он обслужится как воин.
Используй базовые визиторы по отдельности.
Или я что-то недопонимаю?

#33
14:59, 28 мар 2011

Стоп, кажись понял :)

Ну тут да, ты прав. Но по моему небольшой кодо-оверхед лучше чем небольшой скорость-оверхед.

И ты не ответил что делать с ошибками каста:)

#34
15:20, 28 мар 2011

bazhenovc
Ну вот видишь, мы пришли к класической проблематике программирования "CPU, Memory, Development Time"

Напомни, что за ошибки каста?

#35
19:28, 28 мар 2011

IROV..
Если ты случайно передашь туда мусор и каст вернёт 0

#36
19:39, 28 мар 2011

bazhenovc
Динамик каст вернет 0 и....??

        if( TVisitor * p = dynamic_cast<TVisitor*>(_visitor) )
        {
            p->visit(_impl);
        }

тогда мы не войдем в этот if и пойдем дальше.

А что тебя смущает?

#37
19:51, 28 мар 2011

IROV..
И? Exception?

#38
19:54, 28 мар 2011

смотри есть dynamic_cast не сработает (типы разные) то он вернет NULL

тут стоит проверка если не NULL

правильней переписать вот так

TVisitor * p = dynamic_cast<TVisitor*>(_visitor)
if( p != NULL  )
{
    p->visit(_impl);
}

если ноль, мы заканчиваем обработку для этого обьекта.

#39
19:55, 28 мар 2011

bazhenovc
http://ru.wikipedia.org/wiki/Dynamic_cast

#40
20:06, 28 мар 2011

IROV..
Я имею в виду твои действия:) Если визитор должен делать что-то важное, то он просто тупо не отработает? Или ты как-то про это информировать будешь (например исключением)?

По моему втихую скипать объект как то не очень правильно. Надо будет руками добавлять обработку ошибок, а это в свою очередь повысит общую сложность проекта что в свою очередь будет приводить к новым ошибкам.

Хотя можно написать пару лишних строк и оставить проверку типов компилятору, что в свою очередь ещё и быстрее:)

#41
20:30, 28 мар 2011

bazhenovc
На самом деле, "втихую скипать объект" это правильно ;)

#42
20:33, 28 мар 2011

IROV..
Видимо у нас разные взгляды на жизнь:)

#43
22:06, 30 мар 2011

решил собрать свой велосипед ради интереса.

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. +учитывая что статик уже существует до создание объекта то ими можно пользоваться в базовых объектов.

#44
0:13, 31 мар 2011

>>susageP
Срань господня

Страницы: 1 2 3
Архитектура движка.Форум

Тема в архиве.