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