3

我有一个层次结构如下:

         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

4 回答 4

3

您想要做的事情不可能以干净设计的方式进行。我不知道,为什么完全重新编译该层次结构会是这样一个问题,但是有一个解决方案在技术上是可行的,而无需使用 UB 黑客攻击,比如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
这利用了受保护的访问是可传递的这一事实,但代价是您想要从其中获取 num 的每个元素的副本。我将 struct 设为函数本地类,因此没有人会想到将其实际用于任何其他目的。

但请记住,这种技术是一种 hack,是对不应该以这种方式使用的语言功能的利用。

我的建议是:如果你的层次结构在程序中如此纠缠,以至于改变它会给重新编译带来恐惧,那么是时候重构你的程序以减少编译时依赖性,然后做你必须做的改变。

于 2013-04-05T06:58:54.720 回答
0

一种可能性是将 a 声明GetNumVisitor为friend ofElement 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();
 ...
于 2013-04-05T06:16:41.037 回答
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;
     };
于 2013-04-05T06:30:06.330 回答
0

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

一个快速的答案是:不要!这将破坏可见性修饰符的全部目的。但是,使用(导致重新编译层次结构)或通过指针重新解释仍然可以这样做。friend

一个干净的解决方案是使用适配器模式(使用继承)将整个Elements 层次结构复制到另一个存根层次结构中,该存根层次结构为相应函数的委托提供完全相同的接口,为num您的访问者提供一个 getter 函数并使用该新层次结构,这将能够num通过getter访问。

于 2013-04-05T06:33:51.967 回答