使用取消引用的指针的多态性会产生意外的结果.为什么?
Polymorphism with a dereferenced pointer yields unexpected results...why?
我遇到了一个C++难题,可能需要一些帮助! 请考虑以下代码:
#include <iostream>
struct Node
{
virtual void print()
{
std::cout << "Node::print" << std::endl;
}
};
struct Drawable : public Node
{
virtual void print()
{
std::cout << "Drawable::print" << std::endl;
}
};
struct Visitor
{
virtual void apply(Node& node)
{
std::cout << "apply(Node&)" << std::endl;
node.print();
}
virtual void apply(Drawable& drawable)
{
std::cout << "apply(Drawable&)" << std::endl;
drawable.print();
}
};
struct Renderer
{
virtual void accept(Node* node, Visitor* visitor)
{
visitor->apply(*node);
}
};
int main(int argc, char** argv)
{
Renderer r;
Visitor v;
Drawable* drawable = new Drawable();
r.accept(drawable, &v);
return 0;
}
输出为:
apply(Node&)
Drawable::print
我期待调用 Visitor::apply(Drawable&),但 apply(Node&) 被调用。为什么?
看看这行代码:
virtual void accept(Node* node, Visitor* visitor)
{
visitor->apply(*node); // <--- Here
}
当编译器看到此对apply
的调用时,它需要确定您是要调用接受Node&
的apply
版本还是接收Drawable&
的apply
版本。请注意,这是关于选取哪个重载而不是选取哪个覆盖的决定。有关重载的决定是在编译时做出的。在这里,编译器查看表达式*node
并说"好吧,node
是一个Node *
,所以*node
是一个Node&
",因为它在编译时无法知道node
所指向的事物的运行时类型是什么。结果,这将始终调用apply(Node &)
,并且永远不会调用apply(Drawable&)
。
这解释了发生了什么,但你如何解决它?设置访问者模式的传统方法是在类层次结构的底部放置一个这样的函数:
struct Node {
virtual void accept(Visitor* visitor);
};
然后,您将让Node
的每个子类覆盖该函数。然后,每个覆盖将如下所示:
struct Pizkwat: Node {
virtual void accept(Visitor* visitor) override {
visitor->apply(*this);
// do more things, optionally
}
};
在此重写的代码行中,*this
的类型在编译时将与相关对象的类型相同。这意味着重载选择将选择最特定于此类型的apply
版本。
要使用此accept
函数,您可以编写如下内容:
virtual void accept(Node* node, Visitor* visitor)
{
node->accept(visitor);
}
现在,想想会发生什么。accept
成员函数标记为virtual
,因此要调用的accept
的具体版本取决于node
所指向的事物的类型(即它使用动态类型而不是静态类型)。这是使用覆盖解析而不是重载解析。然后,这将调用适当的覆盖,如上所示,该覆盖选择适当的重载。
希望这有帮助!
相关文章:
- 尝试将字符串/字符转换为整数会产生意外结果
- RapidXML - 代码创建意外结果
- 类中静态函数C++意外结果
- 指针数组中的意外结果
- 使用指针访问数组元素时出现意外结果
- 使用 sprintf 和 %g 将双精度转换为字符串的意外结果
- C++:比较运算符>和字符串文本的意外结果
- 具有意外结果的 C++ 闭包
- yaml-cpp 比较的意外结果
- 每次都出现意外结果
- 在 Qt 中解析嵌套的 JSON 时出现意外结果(数组不存在)
- 如何避免 std::abs 的意外结果?
- 使用嵌套 if 语句的意外结果
- A ^= B ^= A ^= B;C# Visual Studio 中的意外结果
- 逻辑错误,我将获得意外结果
- 在 c++ 中使用异步的意外结果
- 从函数的返回值将元素C++存储到 std::vector 中时出现意外结果
- 执行递增和递减时"cout"链接会产生意外结果
- OpenCL - 内核方法返回意外结果
- C++使用 std::get_time 解析 YYMMDD ISO 8601 日期字符串会得到意外结果