Link to home
Start Free TrialLog in
Avatar of pgnatyuk
pgnatyukFlag for Israel

asked on

Visitor pattern

Hi

I have a question about the visitor pattern. Here is an example from evilrix:

 
#include <iostream>

struct CItem1;
struct CItem2;
struct CItem3;

struct Visitor
{
        void visit(CItem1 * p);
        void visit(CItem2 * p);
        void visit(CItem3 * p);
};

struct CItem
{
        virtual void accept(Visitor * p) = 0;
};

struct CItem1 : CItem
{
        void accept(Visitor * p)
        {
                p->visit(this);
        }

        void hello1()
        {
                std::cout << "hello from CItem1" << std::endl;
        }
};

struct CItem2 : CItem
{
        void accept(Visitor * p)
        {
                p->visit(this);
        }

        void hello2()
        {
                std::cout << "hello from CItem2" << std::endl;
        }
};

struct CItem3 : CItem
{
        void accept(Visitor * p)
        {
                p->visit(this);
        }

        void hello3()
        {
                std::cout << "hello from CItem3" << std::endl;
        }
};

void Visitor::visit(CItem1 * p)
{
        p->hello1();
}

void Visitor::visit(CItem2 * p)
{
        p->hello2();
}

void Visitor::visit(CItem3 * p)
{
        p->hello3();
}

void foo(CItem * p)
{
        Visitor v;
        p->accept(&v);
}

int main()
{
        CItem1 i1;
        CItem3 i2;
        CItem3 i3;

        foo(&i1);
        foo(&i2);
        foo(&i3);
};

Open in new window


Simple and nice.
Probably, I do not understand the pattern well. Now without the pattern implemented I have 7 methods like foo(CItem*). In each method I call item->GetType() and then have a switch statement.

So I will have 1 visitor and 7 accept and 7 visit functions?
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

I will look at this in a little bit.
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of pgnatyuk

ASKER

Thanks.
I didn't get the part about " you have resolved from a dynamic to a static type". Why you use these terms "static" and "dynamic"? How it's related to the visitor pattern?
From your answer I already can implement the pattern in my program.
 
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
In acyclic visitor you would need one set of accept/visit for every new class, plus for aggregate visitors like AllVisitor, those must be changed too. In my sample, I added default implementations to Item1Visitor etc., but you can keept those are empty abstract methods if you wish like
struct Item2Visitor : Visitor {
virtual void visit(CItem2 * p) =0;
};
The biggest advantage is the decoupling achieved.
>> I didn't get the part about " you have resolved from a dynamic to a static type".
>> Why you use these terms "static" and "dynamic"? How it's related to the visitor pattern?

See code below to define difference between dynamic and static type and how this relates to the visitor pattern.





struct CItem { virtual ~CItem(){} };
struct CItemEx : CItem{}

foo(CItem* dynamic_type)
{
   // The static type might be CItem  or CItemEx but we don't know without either
   // a discriminator or dynamic_cast but visitor pattern can resolve this for us

   // Let the visitor pattern handle it, dynamic casts are slow and discriminators
   // are ugly and not very OO like, the C++ type system can resolve this for us.
   hello(dynamic_type);
   goodbye(dynamic_type);

}

CItemEx itemEx
foo(&itemEx);

Open in new window

Thanks, evilrix. I think, that's what I need.

ambience, I think, here is a mistake:

void accept(Visitor * p) {
      Item2Visitor* visitor = dynamic_cast(p);
      if(visitor) p->visit(visitor);
}

Anyway, thank you.

int main()
{
	CItem* array[3] = { 0 };
	array[0] = new CItem1;
	array[1] = new CItem2;
	array[2] = new CItem3;
	
	for (int i = 0; i < 3; ++i)
	{
		hello(array[i]);
		goodbye(array[i]);
	}
}

Open in new window

Thank you.