在C ++中的instanceof等价物

时间:2014-12-21 23:58:56

标签: c++ inheritance instanceof

我正在用C ++创建一个使用瓷砖制作的2D游戏。世界级有一个add(WorldObject* o)函数,可以接受一个瓦片或一个实体,比如一个敌人。 TileEntity类都来自WorldObject。在每种情况下,都应将对象添加到entities列表中;但如果它是一个图块,它也应该添加到tiles列表中。

World.h

class World {
private:
    list<WorldObject*> content;
    list<Tile*> tiles;
public:
    void add(WorldObject*);
}

World.cpp

void World::add(WorldObject* o) {
    content.push_back(o);
    if(*o instanceof Tile) //What do I need to put here?
        tiles.push_back(o);
}

如何检查对象在C ++中是否具有特定类型?这与类型转换和虚函数以及类似的东西无关,因为我不想在此时调用对象的函数;如果它有某种类型,我只需要将它添加到一个单独的列表中。 在Java中,我可以if(instance instanceof Class)。我怎么能用C ++做到这一点?

4 个答案:

答案 0 :(得分:10)

dynamic_cast会检查您是否可以将o转发给Tile。如果可以,它将返回有效的Tile*,否则它将返回空Tile*

void World::add(WorldObject* o) {
    content.push_back(o);
    if (Tile* t = dynamic_cast<Tile*>(o)) {
        tiles.push_back(t);
    }
}

答案 1 :(得分:4)

如果对象是多态的,即只有至少一个virtual函数成员,则只能在运行时推断对象的动态类型。一个virtual析构函数也会为此做这件事。 (实际上,如果没有virtual,那么谈论“动态类型”并没有多大意义。)

然后,您可以尝试将dynamic_cast作为instanceof等值。你会写的地方

void f(Base base) {
    if (base instanceof Derived) {
        Derived derived = (Derived) base;
        // use derived
    }
}
在Java中,你会写

void
f(Base& base)
{
  if (Derived * derived_ptr = dynamic_cast<Derived *>(&base))
    {
      // use derived_ptr
    }
}

在C ++中。指针类型的dynamic_cast只会返回nullptr(评估为false),如果对象不是正确的类型,那么它通常会在if内看到。但是,引用的dynamic_cast会引发异常,因此如果您确定该对象实际上属于该类型,则应该只使用它。

我应该补充一点,如果Derived实际上是从Base派生的,那么C ++示例才有效。否则,检查本来是毫无意义的。但请注意,您无法通过void *指针恢复对象的类型。如果你考虑它是有道理的,因为void *实际上可能指向一个随机的字节集合,它没有任何东西从中提取类型。

答案 2 :(得分:2)

你可以这样做:

if(dynamic_cast<Tile*>(o))

这是有效的,因为如果类型不兼容,指针上的dynamic_cast将返回null。当然,空指针是“假的”,因此检查将失败。如果o实际上是Tile,则会产生非空Tile*,并且检查会成功。

答案 3 :(得分:0)

这应该是一个答案,但它可能不是/答案。你做的很糟糕。你会有类似的东西:

void addObject(Object* ob) {
    if(ob->isA()) { doA(ob); }
    if(ob->isB()) { doB(ob); }
    if(ob->isC()) { doC(ob); }
    genericObjectStuff(ob);
}

这是一个“反模式”,因为它很糟糕,它意味着每个派生的(在你的情况下Tile当前是唯一的)你将不得不回到这个功能并添加任何特殊的行为。

有两个修复(取决于游戏中的对象是什么样的)

1)虚拟功能:

void addObject(Object* ob) {
    ob->doSpecificThingYouNeedToDo(this);
    genericObjectStuff(ob);
}

doSpecificThingYouNeedToDo如果它是A doA(this);,如果它是B,那么就做B ......因此你写下它在你定义类的地方时的作用!好多了!

2)你已经抽出太多了!

如果我给你一个DrivableThing你知道你可以做任何意味着成为DrivableThing,你就不会被认为是Truck说的(这是一个DrivableThing)所以你不能loadCargo关于可驾驶的东西,因为它可能不是卡车!

因此,装载货物的功能只能接受Truck或其他可驱动和可装载的类型。有一个装载卡车的通用功能是错误的,但也会在摩托车后面放上比萨饼(交付任务也是!)

这与1相反,而不是向派生类添加功能,您需要仅接受特定对象的不同addObject。因为他们需要这些信息,所以您目前拥有:

void loadUpCargo(DrivableThing* thing) {
    if(thing->isPizzaBike()) { thing->addPizzas(whatever); }
    if(thing->isTruck()) { thing->addCrates(whatever); }
    thing->driveOff(); //we can always drive off DrivableThings
} 

您可以将其更改为:

void loadUpCargo(Truck* truck) {
    truck->addCrates(whatever);
    truck->driveOff(); 
}
void loadUpCargo(PizzaBike* bike) {
    bike->addPizza(whatever);
    bike->driveOff();
}

好多了!

这个经典的例子是“动物类有吃法”,“香蕉是可食用的,猴子是动物”,但有动物和食物不会阻止你喂草给猴子,因为你已经提取了信息远!