【问题标题】:C++: "switch" on actual type given pointer to superclassC ++:在实际类型上“切换”给定指向超类的指针
【发布时间】:2020-12-16 12:55:58
【问题描述】:

假设我有一个名为 Message 的类,其子类为 MessageAMessageB ... MessageZ

也许这些消息位于异构队列中,我正在将它们出列,并且我很肯定它们的父类型是 Message,但我只知道这些。

老 C 程序员可能会在 Message 中放置一个字段,该字段基本上是消息类型的枚举,所以我可以这样做:

switch ( message.ActualMessageType ) {
MessageAType:
   blah blah A
   break;
MessageBType:
   blah blah B
   break;
 :
 :
MessageZType:
   blah blah Z
   break;
}

这很麻烦:当我添加消息子类时,我必须继续编辑那个主枚举定义文件。

对于 C++99,我可能会给 Message 一个名为 BlahBlah() 的纯虚方法,并让每个子类适当地定义它。然后我写的是:

message.BlahBlah();

很好,因为调用虚函数可能比调用 switch 更快(通常实现为跳转查找表,但带有范围检查)。

但是让我们说这个等等等等更干净地属于带有开关的类,而不是那些不需要知道这个特定类如何处理它们的细节的消息。 C++11(或更新的方言?)是否添加了任何有趣的方式来直接跳转到处理各种子消息类型?

例如,如果我调用具有 MessageA 和 MessageB 实现的模板化函数,并带有指向 Message 的指针,其对象实际上是 MessageA 或 MessageB,调用正确的函数吗?

【问题讨论】:

  • 不应该调用一个虚函数来做处理吗?
  • 虚拟方法是你的朋友。
  • 不确定我是否完全理解您试图解决的问题,但您可能想查看visitor patternstd::variantstd::visit
  • 看来您正处于发现virtual 方法的好处的风口浪尖。
  • @SwissFrank - 由实例化消息类的实体来附加处理程序。当您使消息出队时,您将调用处理程序。也许您无法控制消息类的创建,在这种情况下这是不可行的。使用附加函数的好处之一是,如果这样做有好处,可以在运行时更改它们。也就是说,您可以拥有一些处理程序,并根据需要将它们附加到不同的消息类,即使在运行时也是如此。

标签: c++ polymorphism rtti


【解决方案1】:

我认为可能有更好的解决方案,但这里有一个 C++99 解决方案。

Message 类有一个纯虚方法BlahBlah( Processor* )

否则需要 switch 语句的 Processor 将具有称为 BlahBlahA( MessageA* pmsga )BlahBlahB( MessageB* pmsgb )、...BlahBlahZ( MessageZ* pmsgz ) 的方法,它们采用指向相关消息类型的指针

子类MessageA 将定义:

virtual void BlahBlah( Processor* pproc ) { pproc->BlahBlahA( this ); };

Processor 类在它想要进行特定于消息类的处理时会调用:

pmsg->BlahBlah( this );

这会调用BlahBlah() 的每个子类定义,它会调用Processor 类的相应方法。

好处:

  1. 无需维护全局枚举
  2. 所有处理代码都在处理器中,而不是在消息子类中
  3. 无需开关。
  4. 无需演员表、RTTI 等

缺点:

  1. 两个虚函数调用会产生某种开销。

【讨论】:

  • 为什么不让消息调用处理器函数,而不是让消息排队并让处理器告诉消息调用回调函数?
  • @ttemple 有许多不同种类的对象和消息,有些可以立即处理或处理,有些则需要很长时间。创建这些消息的线程,如果它只是简单地调用处理程序,如果一个处理器处理速度很慢,将延迟传递到其他处理器。
猜你喜欢
  • 1970-01-01
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 2011-12-29
  • 2015-04-06
  • 2019-08-28
  • 1970-01-01
相关资源
最近更新 更多