Polymorfism and Abstract class

Hi guys,

i have a situation like this

class Base {...}; //this is an abstract class with one pure virtual method
class Derivate1 : public Base {...};
class Derivate2 : public Base {...};

and i want to develop

class Visitor {
public:
virtual void visit(Derivate1*) = 0;
virtual void visit(Derivate2*) = 0;
};
class ConcreteVisitorA : public Visitor {...};
class ConcreteVisitorB : public Visitor {...};

then basically i have a client class where i would like to do something like

Base* d1 = new Derivate1();
Base* d2 = new Derivate2();

//For example i instantiate a concrete visitor
ConcreteVisitorA vis;
vis.visit(d1);
vis.visit(d2);

i've tried to do something similar but the compiler throw me an error like "ambiguity of the method" or similar.

The idea should be put every specific derivate in a list
std::list<Base*> myList;
for each el in list
vis.visit(el);

is it possible to do something like that?
Yes it is, here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <list>

class Base {
    public:
    virtual void print(void) = 0;
};

class Derivate1 : public Base {
    public:
    explicit Derivate1() : Base() {}
    void print(void) {
        std::cout << "Derivate 1\n";
    }
};

class Derivate2 : public Base {
    public:
    explicit Derivate2() : Base() {}
    void print(void) {
        std::cout << "Derivate 2\n";
    }
};

class Visitor {
    public:
    virtual void visit(Base*) = 0;
};

class ConcreteVisitorA : public Visitor {
    public:
    explicit ConcreteVisitorA() : Visitor() {}
    void visit(Base *base) {
        base->print();
    }
};

int main() {
    // class ConcreteVisitorB : public Visitor {...};
    std::list<Base *> list = {new Derivate1(), new Derivate2()};

    //For example i instantiate a concrete visitor
    ConcreteVisitorA vis;
    for (Base *b : list) {
        vis.visit(b);
    }
    
    return 0;
}


http://cpp.sh/2g6q
Lauke wrote:
1
2
3
4
5
class Visitor {
public:
virtual void visit(Derivate1*) = 0;
virtual void visit(Derivate2*) = 0;
}; 

Should the same thing be done in both cases?
If yes, Base* is the right way to go and you should stop reading here.
Polymorphism is awesome so use it! :D

Otherwise you'll have a hard time to do it using a for Base* loop because the compiler does not know if it is a Derivate1 or Derivaet2.
In that case you might want to give each derivate type an id and resolve the problem with ID's (which is not pretty at all), but at the moment I can't think of an other way.
Note: This option only applies when you do want the visitors to do different things in different derivates.
If you allways want to do the same thing in one derivate, you can just call your virtual function like Smac89 explained to do that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <list>

class Base 
{
public:
    enum { DERIVATE1, DERIVATE2 };
    int id;
    
    virtual void print(void) = 0;

protected:
    Base(int id) : id(id) {}
};

class Derivate1 : public Base 
{
public:
    Derivate1() : Base(DERIVATE1) {}
    void print(void) {
        std::cout << "Derivate 1\n";
    }
};
class Derivate2 : public Base 
{
    public:
    Derivate2() : Base(DERIVATE2) {}
    void print(void) {
        std::cout << "Derivate 2\n";
    }
};

class Visitor 
{
public:
    virtual void visit(Base*) = 0;
};

class ConcreteVisitorA : public Visitor 
{
public:
    ConcreteVisitorA() : Visitor() {}
    virtual void visit(Base* base) 
    {
        switch(base->id)
        {
        case Base::DERIVATE1:
            // do stuff only derivate 1 does
            break;
            
        case Base::DERIVATE2:
            // do stuff only derivate 2 does
            break;
            
        default:
            // do default stuff 
            // for not handled derivates
            break;
        }
        
        // do stuff all derivates have in common
        base->print();
    }
};

int main() {
    // class ConcreteVisitorB : public Visitor {...};
    std::list<Base *> list = {new Derivate1(), new Derivate2()};

    //For example i instantiate a concrete visitor
    ConcreteVisitorA vis;
    for (Base *b : list) {
        vis.visit(b);
    }
    
    return 0;
}

http://cpp.sh/427r




Edit1: you can make the derived classes to register themselves, which would be a better because you don't have to modify the base class every time you add a derivate.

Note: This option also only applies when you do want to do different things with different derivates in different visitors.
If you allways want to do the same in one derivate, you can just call your virtual function to do that.
Note2: You have to split your code in *.cpp and *.h files because of the static variable

Base:

Base.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef BASE_H_
#define BASE_H_

class Base
{
public:
    virtual void print(void) = 0;
    static int count;
    int id;

protected:
    Base(int id) : id(id) {}
};

#endif // BASE_H_ 


Base.cpp
1
2
3
#include "Base.h"

int Base::count = 0;


Derivate1

Derivate1.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef DERIVATE1_H_
#define DERIVATE1_H_

#include "Base.h"

class Derivate1 : public Base
{
public:
    static int id;
    Derivate1() : Base(id) {}
    
    void print(void) { std::cout << "Derivate1\n"; }
};

#endif // DERIVATE1_H_ 


Derivate1.cpp
1
2
3
#include "Derivate1.h"

int Derivate1::id = Base::count++;


Derivate2

Derivate2.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef DERIVATE2_H_
#define DERIVATE2_H_

#include "Base.h"

class Derivate2 : public Base
{
public:
    static int id;
    Derivate2() : Base(id) {}
    
    void print(void) { std::cout << "Derivate2\n"; }
};

#endif // DERIVATE2_H_ 


Derivate2.cpp
1
2
3
#include "Derivate2.h"

int Derivate2::id = Base::count++;


The rest is as nearly the same as it was

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Visitor 
{
public:
    virtual void visit(Base*) = 0;
};

class ConcreteVisitorA : public Visitor 
{
public:
    ConcreteVisitorA() : Visitor() {}
    virtual void visit(Base* base) 
    {
// Sadly, you can't use switch-case here because id cannot be a const expression
        if(base->id == Derivate1::id)
        {
            // do stuff only derivate 1 does
        }
        else if(base->id == Derivate1::id)
        {
            // do stuff only derivate 1 does
        }
        else
        {
            // do default stuff 
            // for not handled derivates
        }
        
        // do stuff all derivates have in common
        base->print();
    }
};

int main() {
    // class ConcreteVisitorB : public Visitor {...};
    std::list<Base *> list = {new Derivate1(), new Derivate2()};

    //For example i instantiate a concrete visitor
    ConcreteVisitorA vis;
    for (Base *b : list) {
        vis.visit(b);
    }
    
    return 0;
}

http://cpp.sh/8alb

Well, that's enough for this topic.

Still note that you should use Smac89's way of doing this if possible.
These examples were just... I don't know, I was interested in the topic.
You can use them if you want to do different things with different visitors with different derived classes
Last edited on
Hi,

I prefer Smac89's version, because it is scalable and takes advantage of polymorphism.

Gamer2015 wrote:

Otherwise you'll have a hard time to do it using a for Base* loop because the compiler does not know if it is a Derivate1 or Derivaet2.


The compiler does know which Derived class it is because it has a pointer to the Derived class object, and a pointer to Derived is a valid pointer to Base.

Your implementation is not scalable because one has to maintain those enums, so it is rather messy if there are lots of new classes to add.

Check out the visitor pattern on wiki:

http://en.wikipedia.org/wiki/Visitor_pattern


Hope all is well for all this Easter :+)
The compiler does know which Derived class it is because it has a pointer to the Derived class object, and a pointer to Derived is a valid pointer to Base.

Naaaaaah not quite.
If i write it like this the compiler calls func(A*) even though a points to a B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

class A {};
class B : public A {};
class C : public A {};

void func(A* a) { std::cout << "a" << std::endl; }
void func(B* b) { std::cout << "b" << std::endl; }
void func(C* c) { std::cout << "c" << std::endl; }

int main(void)
{
    A* a = new B;
    func(a); // calls A

    return 0;
}



I prefer Smac89's version, because it is scalable and takes advantage of polymorphism.

Yeah sure, his method is to be prefered if possible.
I edited my post and added an other way where you have no enums.
(His way still is to be prefered if possible)

My example aims to the problem, that each visitor wants to do something different in each derivate.
I added these examples because he stated in the Visitor base class that he wants to do something different for both cases. (he has 2 different Methods)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ConvenientStore : public Base
{
public:
    std::vector<Good> goods; // pseudocode;
};
class Circus : public Base
{
public:
    std::vector<Actor> actors; // pseudocode;
};

class Visitor
{
public:
    virtual void visit(ConvenientStore * derivate) = 0;
    virtual void visit(Circus * derivate) = 0;
}
class Inspector : public Visitor
{
public:
    void visit(ConvenientStore * derivate) { /* check all goods */ }
    void visit(Circus * derivate) { /* check all actors */ }
}; 
class Customer : public Visitor
{
public:
    void visit(ConvenientStore * derivate) { /* buy food */ }
    void visit(Circus * derivate) { /* watch and enjoy */ }
};


I know this does not work when using Base* but that's where my example came from.

So, not all visitors want to do the same thing in a Circus and in a ConvenientStore.
How would you tackle that problem? (just a rhetoric question but he didn't give more information about what he wants to accomplish)
I hope you know what i mean ._.
Last edited on
Naaaaaah not quite.
If i write it like this the compiler doesn't know what method to call:


That isn't a good example, polymorphism means the use of virtual functions.

With respect, I think you are missing the point with this. The power in the polymorphism comes from 2 things:

1. Virtual functions that do the right thing because a pointer to Derived is a valid pointer to Base.

Your functions have different parameters, so that means writing new function declarations for each new class (as opposed to providing a new implementation for a function in a new class).

We can avoid that - just have a pointer to the Base class as a parameter. The argument is a pointer to Derived class object. So now you can declare an interface of virtual functions (possibly pure) in the Base class, and specialise them where required in Derived classes.

2. The same generalised function names in classes. Well you have that (the visit function). But we can avoid different arguments and overloading.


So, not all visitors want to do the same thing in a Circus and in a ConvenientStore.
How would you tackle that problem?


By specialising the visit function in each derived class.

Note that one can have a container of all different kinds of Derived class objects, and it all still works. As Smac89 does with the std::list , with 2 different derived objects.

With Smac89's code, he could add as many ConcreteVisitor's as he liked, and nothing else would need to change.

Regards:+)
> With Smac89's code, he could add as many ConcreteVisitor's as he liked, and nothing else would need to change.

Smac89's code does not even begin to address the problem that Lauke is trying to solve.

From the wiki article linked to earlier:
In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves;


Gamer2015 > My example aims to the problem, that each visitor wants to do something different in each derivate.

Yes, it does address the problem at hand.

However, favour a run-time cast mechanism over a switch-case construct with manually maintained type fields; it would be more robust (and also more flexible).

For instance, an acyclic version of the visitor, which also allows selective visitation, using dynamic_cast:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <typeinfo>

struct base
{
    struct visitor { virtual ~visitor() = default ;  };

    virtual ~base() = default ;
    virtual void accept( visitor& ) = 0 ;

};

// helper a. defines the interface of the derived class specific visitor 
//        b. provides a canned, reusable implementation of accept()
template < typename DERIVED > struct derive_from_base_helper : base
{
    struct visitor { virtual void visit( DERIVED& ) = 0 ; } ;

    virtual void accept( base::visitor& v ) override
    {
        try { dynamic_cast< visitor& >(v).visit( dynamic_cast< DERIVED& >( *this) ) ; }
        catch( const std::bad_cast& ) { /* ignore the exception: this visitor does not wish to visit us */ }
    }
};

struct A : derive_from_base_helper<A> {};
struct B : derive_from_base_helper<B> {};
struct C : derive_from_base_helper<C> {};
struct D : derive_from_base_helper<D> {};
struct E : derive_from_base_helper<E> {};

int main()
{
    A a ; B b ; C c ; D d ; E e ; D d1 ; B b1 ; D d2 ;
    base* objects[] = { &a, &b, &c, &d, &e, &d1, &b1, &d2 } ;

    struct abe_visitor : base::visitor, A::visitor, B::visitor, E::visitor // // visit only A, B, E
    {
        virtual void visit( A& ) override { std::cout << "abe_visitor::visit A\n" ; } ;
        virtual void visit( B& ) override { std::cout << "abe_visitor::visit B\n" ; } ;
        virtual void visit( E& ) override { std::cout << "abe_visitor::visit E\n" ; } ;
    } abe_v ;

    for( base* obj : objects ) obj->accept(abe_v) ;

    std::cout << "---------------\n" ;

    struct bcd_visitor : base::visitor, B::visitor, C::visitor, D::visitor // visit only B, C, D
    {
        virtual void visit( B& ) override { std::cout << "bcd_visitor::visit B\n" ; } ;
        virtual void visit( C& ) override { std::cout << "bcd_visitor::visit C\n" ; } ;
        virtual void visit( D& ) override { std::cout << "bcd_visitor::visit D\n" ; } ;
    } bcd_v ;

    for( base* obj : objects ) obj->accept(bcd_v) ;
}

http://coliru.stacked-crooked.com/a/be6de8d67db077e5
Last edited on
TheIdeasMan wrote:
That isn't a good example, polymorphism means the use of virtual functions.

It's the same thing in the question asked by Lauke.
The only difference is, that he has these functions in a class.

TheIdeasMan wrote:
By specialising the visit function in each derived class.

And how would you do something different in different classes?


JLBorges wrote:
However, favour a run-time cast mechanism over a switch-case construct with manually maintained type fields; it would be more robust (and also more flexible).

For instance, an acyclic version of the visitor, which also allows selective visitation, using dynamic_cast:

So... A, B, C, D and E are your locations, right?
And your bcd visitor declares what he wants to visit and what he wants to do wherever he visits.

That's awesome *-*
I like it, that's the first time I have seen multiple inheritance im use NOT only from interfaces (aside from the trash code I wrote myself to see how it works)

(I'm still a little bit confused but hey, even more to learn ;D)
Last edited on
Hi guys, i'm sorry for my late response... anyway

The problem is that i would like to have a concrete visitor which has different version of visit, but of course each one of these could do different stuff, like different preprocessing etc. The version of smak89 it's ok but it's visitor has only one method "visit", but if i try to overload such method, with a different parameter, but subclass of Base anyway, it doesn't work (i.e. i have the same error).

by the way... what's the purpose of the explicit keyword?
JLBorges one could be the way you want to be.
(or one of my, far worse, options)

In each concrete visitor class you overload the functions for all locations you want to be able to visit.

All his locations have a visitor struct.
So, all locations have visitors of the type location::visitor.

When making a new Visitor you inherit from the visitor struct of a the locations you want to "be able to go there"


by the way... what's the purpose of the explicit keyword?

That means that implicitly creating that object is not possible.

Here is a better explanaition ^^
http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean
Last edited on
I've always used it myself, but never fully understood it's purpose. According to Google:
Google wrote:
explicit (C++) This keyword is a declaration specifier that can only be applied to in-class constructor declarations. An explicit constructor cannot take part in implicit conversions. It can only be used to explicitly construct an object.


This means that without the explicit keyword, c++ will allow something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

class num {
    int v;
    public:
        num(int v): v(v) {}
        operator int (void) {
            return v;
        }
};

int main() {
    num t = 9 + 8;
    std::cout << (int)t << std::endl;
}


But once you use explicit, num t = 9 + 8; is now an error
Well, it's quite easy to understand though...
When not using the explicit keyword, the compiler is allowed to make "Type Conversions" using a 1-parameter Constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyInt
{
public:
    MyInt() : num() {}
    MyInt(int a) : num(a) {}

    int num;
};

void func(MyInt a){}

int main(void)
{
    // 6 is an integer but a parameter of MyInt is required
    // MyInt has a Constructor which takes 1 int as parameter
    // MyInt(6) is called and therefore a MyInt Object is created
    // When the explicit keyword is used the compiler is not allowed to make a conversion like that
    func(6); 

    return 0;
}
Last edited on
Did OP find a solution to his problem?
Hi,

@JLBorges


As always you have posted some excellent advanced code. I have been reading the wiki page for the Visitor Pattern (VP), and I can see you have implemented (rather already knew about) the Note just below the Java Code.

It seems that the original question fitted squarely around the VP, so I am guessing that's why Smac89 posted his code, which seemed to me to implement the VP. Except that the accept function was named print, which is very misleading. The purpose of the VP is to not add extra functionality to the derived classes, only the accept function.

It's also why I made the comments that I did. In particular my comment about being able to add as many ConcreteVisitor classes as required.

What I should have asked was why the OP wanted to have more than one visit function, because the whole idea is for each derived class to 1 accept function, and then multiple ConcreteVisitor classes which have their own tailored visit function to achieve different functionality.

Maybe it was confusion over the difference between accept and visit functions?

Thanks for your implementation of the wrapper function, I will have lots of use for that.

Regards

Edit: I have read up about the acyclic version of visitor, am now reading about componentization .
Last edited on
> It seems that the original question fitted squarely around the VP

Yes, it does.


> I am guessing that's why Smac89 posted his code, which seemed to me to implement the VP.

No, it emphaticallly does not.

The operation of the visitor has to be polymorphic with respect to objects in two differenct class heirarchies. In languages like C++ that do not support multi-methods, this has to be simulated through double-dispatch.

Gamer2015's approch implemented the second polymorphic dispatch via a switch-case on a type field. The double dispach in my code used a more canonical implemementation: polymorphically dispach a virtual function to a derived class of base, which in turn polymorphically dispacthed another virtual function to a derived class of visitor.


> The purpose of the VP is to not add extra functionality to the derived classes, only the accept function

Repeat: From the wiki article linked to earlier:
In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves;
Last edited on
@JLBorges

Thanks, I see now.

Regards
Topic archived. No new replies allowed.