问题标签 [double-dispatch]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
383 浏览

c++ - 具有双重调度的 C++ 多态循环依赖

所以,我在循环依赖方面遇到了一个大问题。我的 Square.h 和 Circle.h 类都继承了 Shape.h,并使用双重调度来尝试检测两者之间的冲突。我的课程目前按以下方式设置

形状.h

平方.h

圈子.h

本质上,我希望能够做类似的事情

但是当我尝试编译它时遇到了一些错误。显然,包括“Circle.h”在内的 Square.h 将导致一个不会执行的循环循环。有人可以为这个问题提出一个好的解决方案吗?

显然,两个正方形和一个圆形和一个正方形之间的碰撞检测是不同的,所以我需要以某种方式重载这些方法。我认为这将是一个很好的解决方案,任何指针?

错误(这些编译错误相同或 Square.cpp 和 Shape.cpp):

0 投票
3 回答
251 浏览

java - Java Class.cast() 和重载

我正在尝试为小型服务器编写数据包侦听器。我对 Java 很陌生,这是我第一次搞乱网络。整个想法是接收数据包,将数据包ID与其类匹配,将输入流传递给数据包的构造函数,以便可以构造它,然后将其提供给packetHander,每个数据包都有一个重叠的方法。为了实现这一点,我使用了一个数组,该数组将数据包 id 映射到每个类的类,并使用一种称为 decode 的方法来构造数据包。问题是handlePacket 的重载,它的行为不符合预期。让我们看一些代码。

我在线程中运行了数据包侦听器,运行方法如下所示:

decode 和 handlePacket 方法如下所示:

packet_ids 它是一个数组,其中包含对每个数据包类的引用,由它们的 id 索引:

它以这种方式初始化:

如果我执行这个并测试它发送一个类型为 00 的数据包,我得到这个:

所以这意味着 packet00 没有被“handlePacket(Packet00ReqIdentify packet)”处理。如果我在 handlePacket 调用中对“数据包”进行显式转换,它就可以工作。所以问题是:

  • 为什么这不起作用?当我为两者打印类名时,我得到了相同的结果。

  • 我怎样才能让它工作?我已经为此苦苦挣扎了 6 或 7 个小时,阅读、搜索、尝试和查看其他人的代码。一个更简单的解决方案是使用数据包 ID 进行切换,但我想要更优雅的东西。也许我的基本想法是错误的,所以这就是我发布代码的原因,我愿意接受该主题中更有经验的人的建议和想法,包括对该主题材料的推荐。

谢谢!

0 投票
7 回答
766 浏览

c# - .Net 4.0 Optimized code for refactoring existing "if" conditions and "is" operator

I have following C# code. It works fine; but the GetDestination() method is cluttered with multiple if conditions by using is operator.

In .Net 4.0 (or greater) what is the best way to avoid these “if” conditions?

EDIT: Role is part of the business model, and the destination is purely an artifact of one particular application using that business model.

CODE

REFERENCES

  1. Dictionary<T,Delegate> with Delegates of different types: Cleaner, non string method names?
  2. Jon Skeet: Making reflection fly and exploring delegates
  3. if-else vs. switch vs. Dictionary of delegates
  4. Dictionary with delegate or switch?
  5. Expression and delegate in c#
0 投票
2 回答
164 浏览

c++ - 双调度无限循环

B我正在使用双重调度来获取 2 个类 ( , )的 2 个对象之间的距离,C它们是另一个 (A) 的子类。我认为其中的方法class A应该是纯虚拟的,但是它们在其他地方的测试中使用,所以class A必须是可实例化的,所以我不能让它们成为纯虚拟的,对吧?

另一件事是我不确定我是否以一种好的方式使用双重调度,因为有时会Distance(A *a)在基类的定义中生成无限循环。

在中class A,我有方法:

class B

class C

0 投票
1 回答
1939 浏览

c++ - 关于碰撞检测系统中类结构的建议

C++ 是我广泛使用的第一种使用面向对象的语言,所以我对这个想法还是有点陌生​​。我正在尝试将我正在开发的游戏库从 Go(它使用接口而不是真正的 OOP 系统)移植到 C++。

我有一个使用四种类型的碰撞系统:点、边界、线和多边形。我想做的是让所有这些都可以抽象成一个“碰撞器”类,并具有一个能够获取两个碰撞器对象并测试碰撞的函数。它看起来像这样:

最初我想我可以为每种碰撞类型设置方法来测试给定另一种类型的碰撞(即方法 OnPoint、OnBounding、OnLine 和 OnPolygon),然后让“Collider”成为需要所有这些方法的虚拟类,但是然后我意识到这在 C++ 中是不可能的,因为它会使类相互依赖以进行编译(对吗?)。

我有点不知所措,我还能做什么。我的设计理念是白日梦吗?

0 投票
1 回答
108 浏览

c++ - 不使用动态转换复制派生类属性的方法

我试图找到一种有效的方法(使用多态性)在外部复制两个派生类之间的特定属性。我有一组从基类派生的数据类DataClassA。我想在一个单独的过滤器类中对这些数据类进行操作,该过滤器类将DataClassA引用作为输入和输出参数。过滤器将执行常见的必要操作DataClassA,但我还想将特定于类的属性从我的输入传播到输出类。考虑:

我的问题显然是copyAttributes()取决于需要知道输入和输出派生类的类型(不一定要相同)。但是,过滤器只会处理对基类的引用DataClassA。我的反应是简单地制定 a dynamic_cast,尽管我冒着被扇耳光的风险(以及其他可能的负面后果)。如果我这样做,我只需copyAttributes为每个调用copyAttributes父类的派生类创建一个方法,然后使用它dynamic_cast来查看copyFrom对象是否属于同一类型:

我能找到的关于这个问题的最相似的帖子是这里的Virtual functions and polymorphism。我的主要问题是:1)我提议的 dynamic_cast 使用不合适吗?2)如果是这样,我该如何以copyAttributes另一种方式实现?虽然我不确定它会是什么样子,但有一些关于使用访问者设计模式的参考。

这是可视化工具包 (VTK) 所做工作的一种更简单的版本,因为我正在使用对许多不同数据类进行操作的过滤器类。有趣的是,它们通过包含宏来处理 RTTI,这些宏包含类和父类的字符串名称,可以直接进行比较以正确地向下转换数据类型。

0 投票
1 回答
2408 浏览

design-patterns - 访问者选择如何遍历的访问者模式

据我了解,在访问者模式的典型规范中,访问对象决定了如何遍历,一般来说,它们只支持一种遍历顺序。(例如,请参见此处此处。)

是否有同样使用双分派的名称,但访客可以在哪里决定如何遍历对象层次结构?在我的应用程序中,一个非常异构的文档模型类型集合正在向访问者推送,例如导出操作。但是,说各种处理器(访问者)都应该按照广度优先顺序遍历似乎很僵硬。其中一些可能只关注模型的一个子集,或者可能需要以专门的顺序处理模型的某些部分。

我担心以非标准方式使用访问者模式中的名称会混淆其他开发人员。我建议的东西有名字吗?

我还会问是否有理由不让访问者控制遍历,以防万一我错过了通常的访问者公式中的一些智慧。如果可能相关,该应用程序是 Java 版本。

0 投票
1 回答
182 浏览

c++ - 沿模板类使用非虚拟接口向下转换

我正在实现一个有限元代码。

问题描述

在有限元方法中,我们需要一个积分器和一个插值器。积分器是对几何对象进行数值积分的对象,例如四边形、三角形等。积分器在几何对象内部放置多个积分点或横坐标,然后使用插值器逼近这些集成点的功能。

例如,一个四边形对象可以使用一个使用 4 个积分点的积分器。

其中@代表积分点的位置。插值器通过使用角节点处的值(由 * 表示)来近似函数在这些积分点处的值。您可以将其视为@ 的每个值是所有 * 值的一种平均值。

多态性概述

为方便起见,下表显示了此问题中使用的不同类之间的联系:

每个几何形状都有不同的坐标系,所以我的积分器和横坐标如下所示:

积分器.hpp

所有自然坐标横坐标的基类。

横坐标.hpp

四边形横坐标在 ξ 和 η 自然坐标上运行。

Abscissa_Quad.hpp

三角形横坐标在 ζ1、ζ2 和 ζ3 自然坐标上运行。

Abscissa_Tria.hpp

集成器实现将像这样集成:

积分器.cpp

到目前为止,一切都很好。让我向您展示我的插值器类。

插值器.hpp

从插值器中,我派生了所有几何形状的类。您可能会注意到我使用 Interpolator_Template 类作为基础。暂时忽略它,我将在一秒钟内解释细节。此类包含所有四边形共有的函数。

Interpolator_Quad.hpp

这个派生类对应于本题开头画的四边形。推导它的原因是因为可能存在具有更多插值节点的四边形。这个类实现了一个 QUAD_04 元素(一个有 4 个插值节点的四边形),但在有限元素中我们也有 QUAD_08、QUAD_09 等。

Interpolator_Quad_04.hpp

Interpolator_Quad_04.cpp

让我回到我之前错过解释的 Interpolator_Template 类。在我的代码中的某个时刻,我执行从 Abscissa * 到 Abscissa_Quad * 对象的向下转换。我通过将模板类与非虚拟接口模式结合使用来实现这一点。

插值器_模板.hpp

插值器_模板.cpp

我确信这段代码包含错误,因为我只需要复制和粘贴我认为理解我的观点所必需的内容,以及执行修改。但是,我希望我的想法能够正确地通过。

我知道向下转换通常是一种代码味道,所以在我开始为有限元中的所有几何形状实现积分器和插值器之前,我想听听你的意见。

我之前的尝试

这是我实现的最后一个设计模式。我将在下面解释我尝试过的其他设计;但是,您可以跳过阅读本节。

  • 一种双重调度设计模式(特别是访问者模式),其中积分器是派生的而不是插值器。例如,我有一个 Integrator_Quad_04 而不是 Interpolator_Quad_04。Integrator_Quad_04 有一个 Abscissa_Quad 作为成员变量,因为不再派生横坐标。

    然后,插值器成为积分器类的访问者,并访问其 _abscissae 成员变量。我决定不采用这种设计,因为那时插值器必须基于操作而不是形状来实现。

    /li>
  • 我尝试使用多次调度来做一些事情,但是所有形状所需的函数数量增长得非常快。

  • 双调度+模板的多种变体。

  • 我在这里找到了我正在使用的当前设计模式:

    面向对象的设计问题,Liskov 替换原则

结论

正如您可能从代码中推断的那样,我正在使用 C++11 进行编译。

您可能想知道为什么我不简单地将积分器和插值器组合成一个类,答案是因为积分器可能在四边形的子域上操作。例如,我可以在四边形内引入一个虚构的三角形并将积分点放在三角形内,但我仍然会使用四边形插值来近似三角形点内的解。当然,我需要在三角形和四边形坐标之间实现一些映射,但这是另一天的问题。

我想知道你是否认为向下转换不是解决这个问题的好方法,或者我是否遗漏了一些东西。也许我不了解解决此问题的设计模式,或者我的多态架构不正确。

任何反馈表示赞赏。谢谢!

0 投票
1 回答
61 浏览

c# - 如何使用扩展构建双重调度

我有一个类层次结构如下的库:

现在我想根据对象的类型(无论是 A 还是 B)做不同的事情。所以我决定去实现双重调度以避免检查类型。

现在实现双重分派的规范方法是将方法MakeMeDoStuff抽象Base化并在具体类中重载它。但是请记住BaseA并且B在图书馆中,所以我不能自由地添加dos方法。

添加方法扩展不起作用,因为无法添加抽象扩展。

有什么建议吗?

0 投票
3 回答
501 浏览

java - 使用 Java 的双向可扩展层次结构

我的问题是以尽可能可扩展的方式为不同的消息实现不同的行为。我知道访问者模式,我知道双重调度,但我似乎无法找到一个让我满意的解决方案(至少不在 java 的范围内)。

我的情况如下:

我有一个消息层次结构:

消息层次结构

以及路由器接口的层次结构,每个接口都为自己的消息类型定义了一个路由方法:

路由器接口层次结构

我想实现类似于此:

执行

能够添加和删除路由某些消息的能力,以及轻松更改某些消息的路由策略。

问题是,如果不切换我不想做的消息,我无法为界面选择相应的功能,因为类似

会导致java选择重载<runtime message-type>.process(Router)

在编译时,在运行时为相应的路由器对象调用。所以我似乎无法在编译时选择正确的 process() 调用。我也不能反过来做,因为comp.route(msg)

将解决<dynamic router-type>.route(MessageBase)

我可以编写一个访问者,它从 CompositeRouter 中选择正确的方法,但因此我必须使用预先为所有 MessageTypes 定义的相应路由方法来定义访问者接口,这违背了目的,因为这意味着我每当我添加新的 DerivedMessage 时,都必须重写访问者。

有没有办法实现这一点,使得消息和路由器都是可扩展的,或者考虑到当前的 java 特性,它是没有希望的?

编辑1:

我忘了提到的是我有 4 或 5 种其他情况,它们与Router-hierarchy 几乎相同,所以我有点想避免反射进行方法查找,因为我害怕运行时成本。

回复评论:

  1. @aruisdante 关于@bot 建议的假设是正确的。我无法覆盖,因为如果我覆盖路由(MessageBase),我会丢失 MessageBase 的运行时类型。

  2. @aruisdante 和@geceo:我知道我可以做到这一点——这就是我所说的“切换转换”(MessageBase 有一个 MessageType 字段)——但我有 11 个实际消息类和大约 6 个我需要的代码位置,所以这将是一个巨大的痛苦实施 - 以及维护方面。