我的层次结构如下:
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值的层次结构中。但是,这需要再次编译整个层次结构,我们不允许这样做。因此,我们必须以某种方式更改层次结构的设计,以便不需要重新编译层次结构。
答案 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
。