C++ 访问者模式和多态性
C++ Visitor Pattern and Polymorphism
以下代码是我在我的项目中实现的 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);
}
我不明白为什么 class B 的 accept 方法调用的是 visitor(A*) 方法而不是 visitor(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 的继承上 class。我想知道为什么会发生这种情况以及设计具有 "specialized" 访问者的 VisitorPattern 的正确方法是什么(这里 ExtendedVisitor 也可以访问 B 对象)
您的 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;
可以一起驻留在同一个 class 中(它们在您的第二个版本中是重载),那么在这方面它们是不同的方法。
您未正确实施访客。正确的方法是:
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
。
是的 AVisitor
必须了解您的层次结构中的每个 class。这是此模式的主要缺点。
以下代码是我在我的项目中实现的 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);
}
我不明白为什么 class B 的 accept 方法调用的是 visitor(A*) 方法而不是 visitor(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 的继承上 class。我想知道为什么会发生这种情况以及设计具有 "specialized" 访问者的 VisitorPattern 的正确方法是什么(这里 ExtendedVisitor 也可以访问 B 对象)
您的 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;
可以一起驻留在同一个 class 中(它们在您的第二个版本中是重载),那么在这方面它们是不同的方法。
您未正确实施访客。正确的方法是:
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
。
是的 AVisitor
必须了解您的层次结构中的每个 class。这是此模式的主要缺点。