I am trying to implement the visitor pattern in c++ https://en.wikipedia.org/wiki/Visitor_pattern
How can I use this pattern when dealing with objects as their base class? I want the visitor to be able to parse the class hierarchy. In my specific case, not the example I give, I want to parse an array of objects into a json list where each object has both the parent class members and the specific subclass members. Is the visitor pattern not the correct approach here?
#include <iostream>
#include <vector>
class Animal;
class Dog;
class Cat;
class Visitor {
public:
virtual void visit(Animal *a) = 0;
virtual void visit(Dog *d) = 0;
virtual void visit(Cat *c) = 0;
};
struct Animal {
void accept(Visitor &v) { v.visit(this); }
int a;
protected:
Animal(int an) : a(an) {}
};
struct Dog : Animal {
Dog(int dn, int an) : Animal(an), d(dn) {}
void accept(Visitor &v) { v.visit(this); }
int d;
};
struct Cat : Animal {
Cat(int cn, int an) : Animal(an), c(cn) {}
void accept(Visitor &v) { v.visit(this); }
int c;
};
struct ConcreteVisitor : Visitor {
void visit(Animal *a) {
std::cout << "Animal<" << a->a << ">";
}
void visit(Dog *d) {
std::cout << "Dog<" << d->d << ", ";
visit((Animal *)d);
std::cout << ">" << std::endl;
}
void visit(Cat *c) {
std::cout << "Cat<" << c->c << ", ";
visit((Animal *)c);
std::cout << ">" << std::endl;
}
};
int main() {
std::vector<Animal *> animals;
animals.push_back(new Dog(4, 5));
animals.push_back(new Cat(6, 7));
ConcreteVisitor v;
for (Animal *a : animals) {
a->accept(v);
}
}
This prints Animal<5> Animal<7>
You should make accept virtual as well.
Related
Following my previous question, I would like to achieve the following with minimum boilerplate code.
I understand that Kangaru has autowiring feature to reduce code.
Here the original working version of the code.
#include <kangaru/kangaru.hpp>
#include <iostream>
struct IA
{
virtual void run() const = 0;
};
struct A : IA
{
void run() const override
{
std::cout << "A" << std::endl;
}
};
struct IB
{
virtual void runB() const = 0;
};
struct B : IB
{
IA& _a;
B(IA& a)
:
_a (a)
{}
void runB() const override
{
std::cout << "B" << std::endl;
}
};
struct IAService : kgr::abstract_service<IA> {};
struct IBService : kgr::abstract_service<IB> {};
struct AService : kgr::single_service<A>, kgr::overrides<IAService> {};
struct BService : kgr::single_service<B, kgr::dependency<IAService>>, kgr::overrides<IBService> {};
void main()
{
kgr::container container;
container.service<AService>().run();
container.service<IAService>().run();
container.service <BService>().runB();
container.service<IBService>().runB();
}
I have tried the following struct BService : kgr::single_service<B, kgr::autowire>, kgr::overrides<IBService> {}; but it does not work well for me
I have also posted the question in the Kangaru chat, and the author answered to me the following and it works well
#include <kangaru/kangaru.hpp>
#include <iostream>
struct IA
{
virtual void run() const = 0;
};
struct A : IA
{
A()
{
std::cout << "Ctor A" << std::endl;
}
void run() const override
{
std::cout << "A::run" << std::endl;
}
};
struct IB
{
virtual void runB() const = 0;
};
struct B : IB
{
IA& _a;
B(IA& a)
:
_a(a)
{
std::cout << "Ctor B" << std::endl;
}
void runB() const override
{
std::cout << "From B: "; _a.run();
std::cout << "B" << std::endl;
}
};
auto service_map(IA const&) -> struct IAService;
auto service_map(A const&) -> struct AService;
auto service_map(IB const&) -> struct IBService;
auto service_map(B const&) -> struct BService;
struct IAService : kgr::abstract_service<IA> {};
struct IBService : kgr::abstract_service<IB> {};
struct AService : kgr::single_service<A, kgr::autowire>, kgr::overrides<IAService> {};
struct BService : kgr::single_service<B, kgr::autowire>, kgr::overrides<IBService> {};
void main()
{
kgr::container container;
// configure which abstract service will be used
container.emplace<AService>();
container.emplace<BService>();
// Use the abstract serivces
container.service<IAService>().run();
container.service<IBService>().runB();
container.invoke([](IA& a, IB& b) {
a.run();
b.runB();
});
}
I have this problem which I really struggle to even explain(as you can guess by the title) so I'll make it clear by an example
#include <iostream>
using namespace std;
class shape
{
public:
shape()
{
}
};
class triangle : public shape
{
public:
triangle()
{
}
};
class square : public shape
{
public:
square()
{
}
};
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
cout << "Hello, I'm a generic shape\n";
}
};
int main()
{
shape sh;
triangle tr;
square sq;
shape shapeArray[3] = {sh, tr, sq};
shapeTeller tell;
for (auto &element : shapeArray)
{
tell.tellMeWhatShape(element);
}
}
this snippet of code prints three times "Hello, I'm a generic shape", while my desired output would be
"Hello, I'm a generic shape"
"Hello, I'm a triangle"
"Hello, I'm a square"
How can i achieve something like that, considering that I want the array to be of the superclass, and I want it to contains various subclasses?
I also want to make it clear that this is a simplified exhample but in the real implementation I can't use parametric polymorphism cause i want the shapeTeller class' methods to do completely different things.
Thanks a lot
Note: An array can only store a single type of object. A subtype of the object could be an entirely different size which is not something compatible with the way C++ stores arrays.
You could be using std::variant here to allow every array element to store one of several element types here:
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
std::cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
std::cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
std::cout << "Hello, I'm a generic shape\n";
}
void tellMeWhatShape(std::variant<square, triangle, shape> const& s)
{
std::visit([this](auto const& shape)
{
tellMeWhatShape(shape);
},
s);
}
};
int main()
{
shape sh;
triangle tr;
square sq;
std::variant<square, triangle, shape> shapeArray[3] = { sh, tr, sq };
shapeTeller tell;
for (auto& element : shapeArray)
{
tell.tellMeWhatShape(element);
}
}
Alternatively dynamically allocate the shapes and implement the visitor pattern:
class shape;
class triangle;
class square;
struct Visitor
{
virtual void operator()(shape const&) = 0;
virtual void operator()(triangle const&) = 0;
virtual void operator()(square const&) = 0;
};
class shape
{
public:
virtual ~shape() = default;
shape()
{
}
virtual void Accept(Visitor& v) const
{
v(*this);
}
};
class triangle : public shape
{
public:
triangle()
{
}
void Accept(Visitor& v) const override
{
v(*this);
}
};
class square : public shape
{
public:
square()
{
}
void Accept(Visitor& v) const override
{
v(*this);
}
};
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
std::cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
std::cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
std::cout << "Hello, I'm a generic shape\n";
}
};
int main()
{
auto sh = std::make_unique<shape>();
auto tr = std::make_unique<triangle>();
auto sq = std::make_unique<square>();
std::unique_ptr<shape> shapeArray[3] = { std::move(sh), std::move(tr), std::move(sq) };
shapeTeller tell;
struct ShapeTellerVisitor : Visitor
{
ShapeTellerVisitor(shapeTeller& teller)
: m_teller(teller)
{}
shapeTeller& m_teller;
virtual void operator()(shape const& s) override
{
m_teller.tellMeWhatShape(s);
}
virtual void operator()(triangle const& s) override
{
m_teller.tellMeWhatShape(s);
}
virtual void operator()(square const& s) override
{
m_teller.tellMeWhatShape(s);
}
};
ShapeTellerVisitor visitor{ tell };
for (auto& element : shapeArray)
{
element->Accept(visitor);
}
}
Note: You could implement Visitor with shapeTeller directly.
I want to store some data to container. For example I have such code:
#include <iostream>
#include <string>
#include <memory>
#include <map>
class Base
{
public:
Base() {}
virtual ~Base() {}
};
class Class1 : public Base
{
public:
Class1() : Base() {}
~Class1() {}
};
class Class2 : public Base
{
public:
Class2() : Base() {}
~Class2() {}
};
class Class3 : public Base
{
public:
Class3() : Base() {}
~Class3() {}
};
std::map<std::string, std::shared_ptr<Base>> myContainer;
void save(const std::string& id, std::shared_ptr<Base> obj)
{
auto obj1 = std::dynamic_pointer_cast<Class1>(obj);
if (obj1)
{
std::cout << "save obj1" << std::endl;
myContainer.emplace(std::piecewise_construct,
std::make_tuple(id),
std::make_tuple(std::move(obj1))
);
}
auto obj2 = std::dynamic_pointer_cast<Class2>(obj);
if (obj2)
{
std::cout << "save obj2" << std::endl;
myContainer.emplace(std::piecewise_construct,
std::make_tuple(id),
std::make_tuple(std::move(obj2))
);
}
auto obj3 = std::dynamic_pointer_cast<Class3>(obj);
if (obj3)
{
std::cout << "save obj3" << std::endl;
myContainer.emplace(std::piecewise_construct,
std::make_tuple(id),
std::make_tuple(std::move(obj3))
);
}
}
int main()
{
std::shared_ptr<Class1> a1 = std::make_shared<Class1>();
std::shared_ptr<Class2> a2 = std::make_shared<Class2>();
std::shared_ptr<Class3> a3 = std::make_shared<Class3>();
save("id1", a1);
save("id2", a2);
save("id3", a3);
std::cout << "size is " << myContainer.size() << std::endl;
return 0;
}
But function save() has too much complicated implementation. How to make it easier? Somehow to get correct object type and invoke save() once but not in every checking. Maybe it possible to implement it with std::variant or std::tuple? What is much optimized solution you can propose?
You seem to understand virtual functions.
Your entire save function could be implemented as:
void save(const std::string& id, std::shared_ptr<Base> obj)
{
std::cout << "save " << obj->name() << std::endl;
myContainer.emplace(std::piecewise_construct,
std::make_tuple(id),
std::make_tuple(std::move(obj))
);
}
name() would be a virtual function that returns the correct string for the type.
Note that this implementation always saves the pointer passed to it, while your implementation may not save anything.
Assuming you've provide a shared pointer containing the real class instead of a std::shared_ptr<Base> when calling the function, you can rewrite this as a template:
template<class T>
char const* TypeName();
template<>
char const* TypeName<Class1>() { return "obj1"; }
template<>
char const* TypeName<Class2>() { return "obj2"; }
template<>
char const* TypeName<Class3>() { return "obj3"; }
template<class T>
void save(const std::string& id, std::shared_ptr<T> obj)
{
std::cout << "save " << TypeName<T>() << std::endl;
myContainer.emplace(std::piecewise_construct,
std::make_tuple(id),
std::make_tuple(std::move(obj))
);
}
I have the following class architecture:
class Animal
{
// ...
}
class Cat : public Animal
{
// ...
}
class Dog : public Animal
{
// ...
}
// + Several other derived classes
In another section of my code, I have a function that goes through a list of Animals and needs to perform specialized actions in the case of several of the derived classes and a default action otherwise. How can I handle this situation elegantly, given the following constraints:
I'd like to keep the new code outside of Animal and its derived
classes because of separation of concerns.
I'd like to avoid using a switch statement on types or enums as it feels very smelly.
Here's one way - use the concept-model idiom (my name):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
void make_noise_for(const AnimalConcept&)
{
std::cout << "no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
void make_noise() const override {
make_noise_for(static_cast<const Model&>(*this));
}
};
// some models
struct Cat : AnimalModel<Cat>
{
};
struct Dog : AnimalModel<Dog>
{
};
struct Giraffe : AnimalModel<Giraffe>
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat&) {
std::cout << "meow\n";
}
void make_noise_for(const Dog&) {
std::cout << "woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new Cat);
animals.emplace_back(new Dog);
animals.emplace_back(new Giraffe);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
meow
woof
no noise
And here's another way to implement it (this one is nicer since it allows all animals to have unrelated interfaces):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
template<class T>
void make_noise_for(const T&)
{
std::cout << "this animal makes no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
template<class...Args>
AnimalModel(Args&&...args)
: _model { std::forward<Args>(args)... }
{}
private:
void make_noise() const override {
make_noise_for(_model);
}
Model _model;
};
// some models
struct Cat
{
Cat(std::string name)
: _name { std::move(name) }
{}
const std::string& name() const {
return _name;
}
private:
std::string _name;
};
struct Dog
{
Dog(std::string name, int age)
: _name { std::move(name) }
, _age { age }
{}
const std::string& name() const {
return _name;
}
int age() const {
return _age;
}
private:
std::string _name;
int _age;
};
struct Giraffe
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat& c) {
std::cout << c.name() << " says meow\n";
}
void make_noise_for(const Dog& d) {
std::cout << "the dog called " << d.name() << " who is " << d.age() << " years old says woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new AnimalModel<Cat> { "felix" });
animals.emplace_back(new AnimalModel<Dog> { "fido", 2 });
animals.emplace_back(new AnimalModel<Giraffe>);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
felix says meow
the dog called fido who is 2 years old says woof
this animal makes no noise
You can use a combination of the following to get type based dispatch.
Provide for every class to return a type ID associated with it.
Provide a virtual function in the base class to get the type ID associated with an object.
Provide a way for registration of functions based on type ID.
When the time comes for execution of the top level function, search for a registered function given an animal's type ID. If a function is registered, call it. Otherwise, use the default function.
// Implement this function in a .cpp file.
int getNextTypeID()
{
static int typeID = 0;
return ++typeID;
}
class Animal
{
virtual int getTypeID();
};
class Cat : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
class Dog : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
foo.h:
typedef void (*AnimalFunction)(Animal& a);
int registerAnimalFunctor(int typeID, AnimalFunction f);
void foo(Animal& a);
foo.cpp:
typedef std::map<int, AnimalFunction> AnimalFunctionMap;
AnimalFunctionMap& getAnimalFunctionMap()
{
static AnimalFunctionMap theMap;
return theMap;
}
int registerAnimalFunctor(int typeID, AnimalFunction f)
{
getAnimalFunctionMap()[typeID] = f;
return 0;
}
void defaultAnimalFunction(a)
{
// Default action
}
void foo(Animal& a)
{
AnimalFunctionMap& theMap = getAnimalFunctionMap();
AnimalFunctionMap::iterator iter = theMap.find(a.getTypeID());
if ( iter != theMap.end() )
{
iter->second(a);
}
else
{
defaultAnimalFunction(a);
}
}
cat_foo.cpp:
void CatFunction(Animal& a)
{
// Cat action.
}
int dummy = registerAnimalFunctor(Cat::getID(), CatFunction);
dog_foo.cpp:
void DogFunction(Animal& a)
{
// Dog action.
}
int dummy = registerAnimalFunctor(Dog::getID(), DogFunction);
This is the example code I have:
#include <iostream>
#include <vector>
#include <string>
class Animal {
};
class Rabbit : public Animal {
};
class Caller {
public:
virtual void call(Animal* a) {
std::cout << "Caller calls animal" << std::endl;
}
virtual void call(Rabbit* r) {
std::cout << "Caller calls rabbit" << std::endl;
}
};
int main(int argc, char** argv) {
std::vector<Animal*> v;
Caller c;
auto a = new Animal();
auto r = new Rabbit();
v.push_back(a);
v.push_back(r);
for(auto elem : v) {
c.call(elem);
}
return 0;
}
The output of this code can be found here
http://ideone.com/I29g3A
and it outputs:
Caller calls animal
Caller calls animal
I'm wondering, without casting a specific element to Rabbit*, is there a way to get call(Rabbit *r) method to get called?
Sure, e.g., by jumping through a suitable visitor in your system of polymorphic classes. I think you'll need to use two names instead of call(), however. I used pubCall() and call().
#include <iostream>
#include <vector>
#include <string>
class Visitor;
class Animal {
public:
virtual void visit(Visitor&);
};
class Rabbit : public Animal {
void visit(Visitor&);
};
class Visitor
{
public:
virtual void call(Animal* a) = 0;
virtual void call(Rabbit* r) = 0;
};
void Animal::visit(Visitor& v) {
v.call(this);
}
void Rabbit::visit(Visitor& v) {
v.call(this);
}
class Caller
: Visitor {
public:
void pubCall(Animal* a) { a->visit(*this); }
private:
virtual void call(Animal* a) {
std::cout << "Caller calls animal" << std::endl;
}
virtual void call(Rabbit* r) {
std::cout << "Caller calls rabbit" << std::endl;
}
};
int main(int argc, char** argv) {
std::vector<Animal*> v;
Caller c;
auto a = new Animal();
auto r = new Rabbit();
v.push_back(a);
v.push_back(r);
for(auto elem : v) {
c.pubCall(elem);
}
return 0;
}