4

I have a hierarchy as follows:

         class Element{ public : virtual void Accept(Visitor&) = 0
                 protected : Element();   int num;
          };

         class ElementA : public Element{
                 public : ElementA(); 
                 void Accept(Visitor& v) {v.Visit(this};}
         };

         class ElementB : public Element{
                 public : ElementB(); 
                 void Accept(Visitor& v) {v.Visit(this};}


         class Visitor{
                 public: void Visit(ElementA*);
                 void Visit(ElementB*);
         };

EDIT: It is required to add the method int getNum() to the hierarchy that would provide the value of num. However, this will need that the entire hierarchy be compiled again and we are not allowed to do that. So we have to change the design of the hierarchy in a way so that the recompilation of the hierarchy is not needed.

  • How do you intend to return a value from multiple elements? Or can you accept not knowing which value came from which element? – Dariusz Apr 05 '13 at 06:16

4 Answers4

4

What you want to do is not possible in a cleanly designed way. I have no idea, why a complete recompile of that hierarchy would be such a problem, but there is a solution that is technically possible without employing UB hacks like reinterpret_casting the access protection away and other hacks.

int Visitor::getNum(Element* pe)
{ 
  //define a pick-pocket... ;)
  struct ElementNumAccessor : private Element
  {
    ElementNumAccessor(Element const& e) : Element(e) {}   
    int getNum() { return num; }

    void Accept(Visitor&); //has to be declared, but needs not be defined
  };

  //...and let him work:
  ElementNumAccessor ea(*pe);
  return ea.getNum();
}

This soultion in action: http://ideone.com/e1chSX
This exploits the fact that protected access is transitive, but comes at expense of a copy of each element you want the num from. I made the struct a function local class, so that nobody gets the idea to actually use it for any other purpose.

But bear in mind that this technique is a hack, an exploit of a language feature that is not meant to be used this way.

My advice would be: If your hierarchy is so entangled in the program that changing it leaves to a recompilation horror, then it's about time to refactor your program to reduce compiletime dependencies and then do the changes you have to do.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • changed it a bit - you don't have to copy the Elements – Arne Mertz Apr 05 '13 at 07:02
  • Hmm, is that allowed? You are accessing a protected member of an argument that is not of the same class. I know your suggestion will work if you took ElemNumAccessor as input, like `getNum(ElemNumAccessor)` (since access restrictions are per-class, rather than per-member). But accessing members of a base class argument should not work: http://stackoverflow.com/questions/7476117/cannot-access-protected-member – maditya Apr 05 '13 at 07:06
  • hm I'll look it up - stay tuned – Arne Mertz Apr 05 '13 at 07:12
  • Sure. :) The question still seems fishy, but this is a nice way around it. – maditya Apr 05 '13 at 07:25
0

One possibility is to declare a GetNumVisitor as friend of Element class and access the num member variable directly. Then add a method in the GetNumVisitor to return the value.

class Element { 
  ...
  friend GetNumVisitor;  // declare GetNumVisitor as a friend class
  ...
};

GetNumVisitor : public Visitor {
 private: 
  int  m_numelement;
 public : 
  void visit(Element *E) { m_elementNum = E->num; }
  int getNum() const { return m_elementNum;}
};

You will have to call it as

 ElementA element_a();
 ElementB element_b();
 GetNumVisitor getnumVisitor();
 element_a.accept(getnumVisitor);
 int a = getnumVisitor.getNum();
 element_b.accept(getNumVisitor);
 int b = getnumVisitor.getNum();
 ...
FKaria
  • 1,012
  • 13
  • 14
  • declaring GetNumVisitor a friend of Element will lead to recompilation of Element and thus of any class that uses Element - meaning the whole hierarchy. You could as well add a method `getNum()` to Element, it would technically have the same consequences in terms of compilation dependencies. – Arne Mertz Apr 05 '13 at 06:35
0

Not an expert on the visitor pattern, but does this fit your requirements?

    class Element{ public : virtual void Accept(Visitor&) = 0
             protected : Element();   int num;
      };

     class ElementA : public Element{
             public : ElementA(); 
             void Accept(Visitor& v) {v.setNum(this->num); v.Visit(this);}
     };

     class ElementB : public Element{
             public : ElementB(); 
             void Accept(Visitor& v) {v.setNum(this->num); v.Visit(this);}


     class Visitor{
             public:
             void Visit(ElementA*);
             void Visit(ElementB*);
             void setNum(int _num) {num = _num;}
             int getNum() {return num;}

             private:
             int num;
     };
maditya
  • 8,626
  • 2
  • 28
  • 28
  • He is not allowed to recompile the `Element`* hierarchy! – Y.H. Apr 05 '13 at 06:35
  • Sorry, for some reason I thought modifying the interface was the thing that was not allowed. In my solution, if the Accept functions are implemented in a .cpp he can get away with not modifying the interface, although you're right that he would have to recompile. – maditya Apr 05 '13 at 06:40
  • The issue I'm having trouble with is that `num` is protected ... how are you supposed to access it from Visitor? Either you have to add getNum to the Element class, or you have to make Visitor a friend of Element - both of which require recompiling ... – maditya Apr 05 '13 at 06:49
  • I can only think of pointer reinterpretation which is *not* recommended and will probably lead to undefined behavior. So maybe the answer is that it is simply not possible. – Y.H. Apr 05 '13 at 06:56
0

Your question is how to allow a class (Visitor) to directly access a private data member inherited in a different class hierarchy (Elements).

A quick answer would be: Don't! this will break the whole purpose of visibility modifiers. However doing this is still possible using friend (leads to recompilation of hierarchy) or via pointers reinterpretation.

A clean solution would be to use adapter pattern (using inheritance) to duplicate the whole Elements hierarchy into another stub hierarchy that provides exactly the same interface with delegates to corresponding functions, provide a getter function for num and use that new hierarchy with your visitor which will be able to access num via the getter.

Community
  • 1
  • 1
Y.H.
  • 2,687
  • 1
  • 29
  • 38
  • Pointers reinterpretation to access private members is UB - read "pure evil", although it will work in many systems. Befriending some other class would be a needlessly tight coupling and lead to recompilation of the whole hierarchy which is a no-go for the OP. But luckily the num is not private but protected... – Arne Mertz Apr 05 '13 at 06:40
  • I also think using pointers reinterpretation is not a good idea. However I am interested in your last sentence, what difference does using protected instead of private in this case? – Y.H. Apr 05 '13 at 06:48
  • @Arne, as I understand it, the main difference between private and protected is that the latter gives the derived class access to the base class. But what use is this if you're not allowed to modify the classes (i.e. recompile)? Or am I misunderstanding that part? – maditya Apr 05 '13 at 06:53
  • see my answer - you can derive from Element to create a pick-pocket that accesses other Elements ;-) – Arne Mertz Apr 05 '13 at 06:59
  • Ah, this is exactly what I was thinking about after reading your comment! adapting the whole hierarchy into a stub hierarchy using private inheritance. Have an upvote! :-) – Y.H. Apr 05 '13 at 07:05