以下代码是我在项目中实现的VisitorPattern的简化版本。
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
};
class ExtendedVisitor : public AVisitor {
public:
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //why this calls to visit(A*)
visitor->visit((B*) just_this); //useless casting
}
};
class ActualVisitor : public ExtendedVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Never called" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
我不明白为什么B类的accept方法调用访问者(A *)方法而不是访问者(B *)。主要功能打印
Call accept of B
Call visit on A*
Call visit on A*
相反,以下代码的行为符合我的预期:
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //now it works
visitor->visit((B*) just_this);
}
};
class ActualVisitor : public AVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Call visit on B*" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
现在打印:
Call accept of B
Call visit on B*
Call visit on B*
然后问题似乎是AVisitor类的继承。我想知道为什么会发生这种情况以及设置带有“专门”访问者的VisitorPattern的正确方法(此处ExtendedVisitor也可以访问B对象)
答案 0 :(得分:1)
您的B::accept
具有以下签名:
void accept(AVisitor *visitor) override;
所以,让我们检查一下AVisitor
的界面。它有
virtual void visit(class A *) = 0;
这就是它的全部(在你的第一个版本中)。确实ExtendedVisitor
有
virtual void visit(class B *) = 0;
但是不会覆盖AVisitor
中的方法。事实上,您的第二个版本可以帮助您了解原因。由于
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
可以一起存在于同一个类中(它们是第二个版本中的重载),然后它们就是这方面的不同方法。
答案 1 :(得分:0)
您正在错误地实施访问者。这是正确的方法:
private ImageView iv;
private Button btn;
int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
iv = (ImageView) findViewById(R.id.iv);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(i>3){
i=i%3;
}
ObjectAnimator oa2= ObjectAnimator.ofFloat(iv, "rotation", i*90,(i+1)*90);
oa2.setDuration(1000);
oa2.start();
i++;
}
});
}
然后
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
// virtual void visit(class C *) = 0; etc
// a separate function for every class in your hierarchy
};
不需要class ActualVisitor : public Visitor ...
。
是ExtendedVisitor
必须了解层次结构中的每个类。这是这种模式的主要缺点。