在没有dynamic_cast的大层次结构中确定基指针的真实类型
Posted
技术标签:
【中文标题】在没有dynamic_cast的大层次结构中确定基指针的真实类型【英文标题】:Determine real type of base pointer in a big hierarchy without dynamic_cast 【发布时间】:2018-07-27 16:10:07 【问题描述】:假设我有一个抽象基类State
和至少两个派生类AnimalState
和PlantState
(也是抽象的)。另外,我有很多来自AnimalState
和PlantState
的派生类。
class State // abstract
class AnimalState: public State // abstract
class PlantState: public State // abstract
//maybe few more of such classes here
class AnimalStateSpecific1: public AnimalState
class AnimalStateSpecific2: public AnimalState
... //many of them
class PlantStateSpecific1: public PlantState
class PlantStateSpecific2: public PlantState
... //many of them
现在假设,我在某种基于State
指针的方法中使用它们。随着时间的推移,这些指针被替换为指向来自State
层次结构的不同类的其他指针。它按照某种规则发生,特别是在预定义的状态图中。
现在到问题部分。为了确定下一个状态,我需要知道前一个状态。但是由于我只有基本的State
指针,我无法有效地判断我拥有什么类型的状态,而不对层次结构中的每个不好的派生类执行dynamic_cast
。我可以拥有一些 enum
与我拥有的各种状态,但我不太喜欢这样,因为我不想混合来自两个层次结构分支的信息,因为它确实不同。此外,我不喜欢层次结构中的每个分支都使用不同的enums
,例如AnimalStateEnum
、PlantStateEnum
等。
这个问题的最佳解决方案是什么?也许我的设计从一开始就不好?如果可能的话,我想让它尽可能通用,并且只使用基类对象。
【问题讨论】:
如果您真的需要知道State*
的实际类型,您可能会错过界面中的某些内容。
您可以使用double-dispatch 或为std::type_index 的类型生成索引。
您可能对我一直在为 STTCL 使用的设计模型感兴趣,您也可以将其用作框架,从 Harel (UML) 状态图中对您的状态机进行建模。跨度>
【参考方案1】:
现在到问题部分。为了确定下一个状态,我需要知道前一个。
基于我们拥有的有限信息的最简单解决方案 - 对象,它知道自己的状态创建下一个状态对象:
class State
public:
...
virtual std::unique_ptr<State> transform( some data ) = 0;
;
然后你在每个派生自State
的类中实现它,它可以改变它的状态并知道它可以移动到哪里。您需要传递哪些数据不是一个简单的问题 - 它取决于您的任务并且可能有各种选项,但是您需要定义所有派生类都可以使用的东西,因为签名在基类上定义并在所有类上共享派生的。
这个问题的最佳解决方案是什么?也许我的设计一开始就不好?
这个问题不是微不足道的,只有对你的任务有相当深入的了解才能回答。如果您不确定 - 实施原型并检查解决方案是否适合您的问题。不幸的是,学习如何创建一个好的设计的唯一方法是你自己的经验(当然除了琐碎的案例)。
【讨论】:
这个对我来说看起来很有前途。谢谢,我会试试你的答案。 我在尝试了不同的方法后选择了这个。此外,所有的 cmets 对问题的理解都非常有帮助。谢谢!【参考方案2】:你可以在状态类层次结构中简单地有一个虚拟方法next()
,
然后执行类似于以下示例的操作:
State *globalState = nullptr;
void foo(State *s)
globalState = s->next();
每个派生类都会按照自己的含义实现next()
:
PlantStateSpecific1 *AnimalStateSpecific1::next() return new PlantStateSpecific1;
AnimalStateSpecific1 *PlantStateSpecific1::next() return new AnimalStateSpecific1;
这比拥有派生类的枚举/整数描述符更具 OOP。
【讨论】:
您几乎不应该将原始指针返回到动态分配的内存。 @Slava 我同意。这只是一个单行 POC 实现来展示这个想法。【参考方案3】:你可以在基本状态类中拥有一个整数,它下面的每个类都将在其构造函数中设置。然后,您可以使用常量序列、可能状态列表,其 id 对应于状态类型索引,或者使用枚举器。 id 更灵活,因为您可以相对轻松地创建状态类型并轻松地添加处理它们,以及如果您想从 id 类型创建新状态。
这只是 iv 以前做过的一种方式,但可能还有很多其他方式。
【讨论】:
我在我的问题中写道,我不喜欢枚举的想法,因为所有的状态都会被混合到一个大列表中。以上是关于在没有dynamic_cast的大层次结构中确定基指针的真实类型的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 unique_ptr 执行 dynamic_cast?