在没有dynamic_cast的情况下确定大型层次结构中基本指针的真实类型

时间:2018-07-27 16:10:07

标签: c++ inheritance

假设我有一个抽象基类State和至少两个派生类AnimalStatePlantState(也是抽象的)。另外,我有许多来自AnimalStatePlantState的派生类。

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,但是我真的不喜欢那样,因为我不想混合来自两个层次结构分支的信息,因为这确实是不同的。另外,对于层次结构中的每个分支,例如enumsAnimalStateEnum等,我都不喜欢不同的PlantStateEnum

此问题的最佳解决方案是什么?也许我的设计从一开始就不好?我想使其尽可能通用,并且仅在可能的情况下仅与基类对象一起使用。

3 个答案:

答案 0 :(得分:2)

  

现在到问题部分。为了确定下一个状态,我需要知道上一个状态。

基于我们拥有的有限信息的最简单解决方案-对象,它知道自己的状态会创建下一个状态对象:

awscli           1.15.66  
blessed          1.15.0   
botocore         1.10.65  
cement           2.10.12  
certifi          2018.4.16
chardet          3.0.4    
colorama         0.3.9    
docker-py        1.10.6   
docker-pycreds   0.3.0    
dockerpty        0.4.1    
docopt           0.6.2    
docutils         0.14     
idna             2.7      
jmespath         0.9.3    
pathspec         0.5.6    
pip              18.0     
pyasn1           0.4.4    
python-dateutil  2.7.3    
PyYAML           3.13     
requests         2.19.1   
rsa              3.4.2    
s3transfer       0.1.13   
semantic-version 2.6.0    
setuptools       40.0.0   
six              1.11.0   
texttable        1.4.0    
urllib3          1.23     
wcwidth          0.1.7    
websocket-client 0.48.0   
wheel            0.31.1 

然后在从class State{ public: ... virtual std::unique_ptr<State> transform( some data ) = 0; }; 类派生的每个类中实现它,可以更改它的状态并知道它可以移动到哪里。您需要传递什么数据不是一个简单的问题-它取决于您的任务,并且可能具有各种选项,但是您需要定义一些可以被所有派生类使用的东西,因为签名是在基类上定义并在所有派生的。

  

此问题的最佳解决方案是什么?也许我的设计从一开始就不好?

这个问题并不简单,只有对您的任务有很深的知识才能回答。如果不确定,请实施原型并检查解决方案是否完全适合您的问题。不幸的是,学习如何创建好的设计的唯一方法是您自己的经验(当然,平凡的情况除外)。

答案 1 :(得分:1)

您可以在状态类层次结构中简单地使用虚拟方法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。

答案 2 :(得分:0)

您可以在基态类中包含一个整数,该类下的每个类都将在其构造函数中设置该整数。然后,您可以使用常量的Sereis,具有与状态类型索引相对应的ID的可能状态的列表,或使用枚举器。 id更加灵活,因为您可以相对轻松地创建状态类型并轻松地对其进行添加处理,以及您希望从id类型创建新状态。

iv以前只是这样做的一种方式,但可能还有很多其他方式。