0

I have the following code :

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

class MyVisitor
{
   public:
       void visit(B*);
       void visit(C*);
};

And then collection of A* objects, I want to achieve the following :

1)

MyVisitor visitor;
for(vector<A*>::iterator it = vec.begin(); it!= vec.end();it++)
     visitor->visit(a);

2) Somehow determine at compile time, if A* points to derived object D,and give compiler error, if MyVisitor::visit(D*) function is not present

I know that 1) is achievable with some multimethods implementation, I guess I can find some implementations of multimethods for c++ . But is 2) somehow possible ?

quantdev
  • 23,517
  • 5
  • 55
  • 88
user152508
  • 3,053
  • 8
  • 38
  • 58
  • By "multimethod" I assume you mean polymorphic cast? Do you come from a Clojure background? – Sir Digby Chicken Caesar Aug 29 '14 at 07:30
  • @SirDigbyChickenCaesar multimethods are a language agnostic notion (a.k.a. multiple dispatch) – sehe Aug 29 '14 at 07:31
  • Regardless, there is no way to determine (within c++'s type system at least) whether or not some arbitrary INSTANCE of a class is a derived or base class at COMPILE time after instantiation. – Sir Digby Chicken Caesar Aug 29 '14 at 07:41
  • It misses the `accept` part in the hierarchy for the [Visitor_pattern](http://en.wikipedia.org/wiki/Visitor_pattern) – Jarod42 Aug 29 '14 at 07:43
  • 1
    Perhaps the techniques based on Boost Variant (with binary visitation) will interest you: http://stackoverflow.com/questions/18859699/generating-an-interface-without-virtual-functions/18859931#18859931 (I can't find the other example that may have been a better match right now) – sehe Aug 29 '14 at 07:50
  • Maybe you want to take a look at some projects I have developed: http://www.yorel.be/mm/, https://github.com/jll63/yomm11, http://www.codeproject.com/Articles/635264/Open-Multi-Methods-for-Cplusplus11-Part-1 It is an implementation of multi-methods for C++ that very much resembles Stroustrup & al's proposal. It is fast too, it beats double dispatch. – yorel Aug 29 '14 at 14:44

3 Answers3

2

You could use dynamic_cast like this (inside the body of your for loop) since the behavior should vary at run-time (according to the actual type of data).

   ClassB* ba = dynamic_cast<ClassB*>(a);
   if (ba)
      visitor->visit(ba);
   ClassC* ca = dynamic_cast<ClassC*>(a);
   if (ca)
      visitor->visit(ca);

Maybe your visit functions might be declared virtual (for your ClassD thing).

Otherwise organize your classes as a tree (not a forest) of classes, and have your topmost root class

  class Topmost {
     virtual int classnum() const;

and adopt the convention that each non-abstract class gives its unique classnum etc... Or have a metaclass mechanism (like e.g. Qt has)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

You can try something like this.

#include <iostream>

class A
{
    virtual void visit() = 0;
};
class B: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }
};
class C: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }    
};

template <typename... Args>
class MyVisitor : public Args...
{
   public:
       template <typename T>
           void visit(T* t)
       {
           t->visit();
       }
};

int main()
{
    MyVisitor<B, C> visitor;
    B b;
    B* bp = &b;
    visitor.visit(bp);
    return 0;
}

Live example

  • Why the derivation from `Args...`? And you could pass any unrelated type that has a `visit` method, including something that doesn't derive from `A` at all. – WhozCraig Aug 29 '14 at 07:48
0

You may apply the visitor pattern completly:

class B;
class C;

class IVisitor
{
public:
    void visit(B&) = 0;
    void visit(C&) = 0;
};

class A
{
    virtual ~A() = default;
    virtual void accept(IVisitor& v) = 0;
};

class B: public A{ void accept(IVisitor& v) override { v.visit(*this); } };
class C: public A{ void accept(IVisitor& v) override { v.visit(*this); } };
Jarod42
  • 203,559
  • 14
  • 181
  • 302