【问题标题】:Check the type of derived class检查派生类的类型
【发布时间】:2012-05-07 13:51:10
【问题描述】:

在我的程序中,我有一个名为 Entity 的类。另一个类 Invader 继承了 Entity。由于我想拥有 4 种不同类型的入侵者,我声明了继承自 Invader 的类 Invader1、Invader2、Invader3 和 Invader4。现在我声明一个实体指针类型向量来存储所有入侵者,例如:

entities.push_back(new Invader4());
entities.push_back(new Invader3());
entities.push_back(new Invader2());
entities.push_back(new Invader1());
entities.push_back(new Invader0());

当我在运行时检查实体中元素的类型时,比如说

typeid(*entities->at(index)) 

它可能会返回四种入侵者之一。在实体中还有其他继承实体的对象。所以我只想检查对象的类型是不是Invader,我不想知道它是Invader1,Invader2等等。

我怎样才能做到这一点?

【问题讨论】:

  • 在运行时需要知道类表明设计不好。你到底想做什么?

标签: c++


【解决方案1】:

在 C++ 中有很多方法可以做到这一点,但基本问题是,一旦您必须开始查询应该是多态的容器中的元素,您可能会放弃使用多态的想法。拥有多态元素集合的全部意义在于您可以对它们一视同仁。所以如果你有一个vector<Entity*>,你应该只把它的元素当作Entity*s。如果你发现你需要在 Entity 上调用一些类似于 Invader 的函数,那么你最好也持有一个 Invader* 的容器(使用与原始容器相同的指针)。

【讨论】:

  • 我完全同意。这就是 liskov 原则的重点!
  • 是的,你是对的。当你尝试使用多态性时,使用类型检查有点尴尬。但在极少数情况下,我似乎必须检查类型并使对象的功能有所不同。生病尝试改进我的程序的结构。感谢您的帮助!
【解决方案2】:

您可以检查dynamic_cast<Invader*>(entities->at(index)) 是否返回不是NULL(因为当指针未指向其类派生自Invader 的对象时,它会导致NULL 指针)。

有关一些文档,请参阅 this link

【讨论】:

    【解决方案3】:

    创建一个继承自EntityInvader 类。让您的Invader1Invader2 等类继承自Invader

    然后您可以添加一个virtual bool IsInvader() const;,它在Entity 中返回false,在Invader 中返回true

    【讨论】:

    • 然后在每次编写派生自Entity的类时将isWhatever()添加到Entity
    • @juanchopanza 那么virtual const char* getClassName() const; 呢?
    • @moooeeeep 几乎一样糟糕。必须查询“多态”集合中的每个元素的设计失去了多态的所有好处,并且根本无法扩展。
    • @juanchopanza 我的查询不是“每次编写派生自 Entity 的类时对 Entity 的 isWhatever()?”。这显然是一个布尔查询,它捕获某些实体的共同属性,尽管不是全部。您正在查询某个语义属性,该属性恰好在逻辑上与类型相关联,而不是类型本身。
    【解决方案4】:

    仅仅问这个问题通常意味着你实际上在你的界面中缺少一个虚函数。

    如果你有类似的东西:

    if (myEntity->Type() == TypeInvader)
    {
      static_cast<Invader*>(myEntity)->invade();
    }
    

    你几乎可以肯定地通过添加来重构它

    virtual void tryInvade() {/* normally, entities don't invade*/}
    

    在您的实体中和

    virtual void tryInvade() {invade(); /*but invaders do!*/}
    

    在你的 Invader 类中。

    另一种选择是永远不要“丢失”实体的类型。如果您不想在这种情况下使用虚函数,很可能您不应该通过引用它们的基类指针来存储这些实体,而是作为指向您实际想要使用的类的指针。也就是说,您只需保留实体的类型,而不是稍后再请求它。这可能表明您不应该使用继承,因为您会违反 liskov substition principle 相应的存储。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      • 2011-02-01
      • 1970-01-01
      • 2018-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多