从访客模式返回值

时间:2013-04-05 05:51:03

标签: c++ design-patterns visitor

我的层次结构如下:

         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*);
         };

修改 需要将方法int getNum()添加到提供num值的层次结构中。但是,这需要再次编译整个层次结构,我们不允许这样做。因此,我们必须以某种方式更改层次结构的设计,以便不需要重新编译层次结构。

4 个答案:

答案 0 :(得分:3)

以简洁的设计方式无法实现您的目标。我不知道,为什么完全重新编译该层次结构会出现这样的问题,但是有一种解决方案在技术上是可行的,而不会使用UB hack,例如reinterpret_cast访问保护和其他黑客攻击。

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();
}

这种行动中的灵魂:http://ideone.com/e1chSX
这利用了受保护访问是可传递的这一事实,但却以您想要数字的每个元素的副本为代价。我使struct成为一个函数本地类,因此没有人会想到将其实际用于任何其他目的。

但请记住,这种技术是一种黑客攻击,是一种语言功能的利用,并不是以这种方式使用的。

我的建议是:如果您的层次结构如此纠缠在程序中,将其更改为重新编译恐怖,那么现在是时候重构程序以减少编译时依赖性,然后进行必须进行的更改。

答案 1 :(得分:0)

一种可能性是将GetNumVisitor声明为Element class的朋友并直接访问num成员变量。然后在GetNumVisitor中添加一个方法以返回值。

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;}
};

您必须将其称为

 ElementA element_a();
 ElementB element_b();
 GetNumVisitor getnumVisitor();
 element_a.accept(getnumVisitor);
 int a = getnumVisitor.getNum();
 element_b.accept(getNumVisitor);
 int b = getnumVisitor.getNum();
 ...

答案 2 :(得分:0)

不是访问者模式的专家,但这是否符合您的要求?

    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;
     };

答案 3 :(得分:0)

您的问题是如何允许类(Visitor)直接访问在不同类层次结构(Element s)中继承的私有数据成员。

快速回答是:不要!这将破坏可见性修饰符的整个目的。 但是这样做still possible使用 friend (导致重新编译层次结构)或通过指针重新解释。

一个干净的解决方案是使用adapter pattern(使用继承)将整个Element层次结构复制到另一个存根层次结构中,该层次结构提供与相应函数的委托完全相同的接口,提供getter函数对于num并使用您的访问者的新层次结构,该访问者可以通过获取者访问num