如何找出变量的类型,涉及继承/多态

时间:2012-01-06 20:03:16

标签: c++ inheritance types

如果涉及继承,我如何找出变量的类型?

我有一点情况,我会用伪代码描述它:

class A
{
public:
A();
virtual ~A();

protected:
//some members
};

class B : public A
{
public:
B();
virtual ~B();

protected:
//some members
};

///////////////////////

int main()
{
A* pA = new B();
std::cout<<"type of pA: "<< ???;
}

如何找出pA的类型?结果应该是B.另外,如果我希望结果是A,我该怎么办?

感谢。


编辑:

我会让你判断它是否是糟糕的设计。如果你认为是,那么请告诉我一个更好的选择。

代码:

class MyContactReport : public NxUserContactReport
{
    void OnContactNotify(NxContactPair& pair, NxU32 events)
    {
        if (pair.actors[0]->userData == NULL || pair.actors[1]->userData == NULL) return;

        LevelElement* otherObject = (LevelElement*)pair.actors[1]->userData;
        LevelElement* triggerObject = (LevelElement*)pair.actors[0]->userData;

        switch(events)
        {
        case NX_NOTIFY_ON_START_TOUCH:
            triggerObject->OnContactStartTouch(otherObject);
            break;
        case NX_NOTIFY_ON_END_TOUCH :
            triggerObject->OnContactEndTouch(otherObject);
            break;
        case NX_NOTIFY_ON_TOUCH:
            triggerObject->OnContactTouch(otherObject);
            break;
        }
    }
} *myReport;

pair.actors[1]->userData让我可以访问演员的userData,演员是PhysX框架的一部分,它决定了碰撞和物理等。用户数据的类型为void*。 这也是找出演员实际所属的对象的唯一方法。

然后是class LevelElement,一个抽象类,我的关卡中的每个对象都继承自(级别,如游戏级别)

LevelElement已保护虚拟方法:OnContactTouch(LevelElement* pOtherElement)等... 在这些方法中,我需要找出它是什么类型的LevelElement,采取某些特定的措施。

这是一个糟糕的设计吗?如果是,请帮忙!

4 个答案:

答案 0 :(得分:3)

使用typeid运算符,例如here

所述

基本上:

#include <typeinfo>

[...]

std::cout << "typeid(*pA): " << typeid(*pA).name() << std::endl;
std::cout << "typeid(pA): " << typeid(pA).name() << std::endl;

结果,使用g ++ 4.4.5:

typeid(*pA): 1B
typeid(pA): P1A

即。至少使用gcc有一些涉及到的错误。查看this question了解如何处理此问题。


编辑:至于你的设计问题,不是检查otherObject是什么类型,更好的解决方案就是告诉这个对象该做什么。假设您想为onContactTouch编写一个假设的Bullet对象;而不是

switch (type) {
case PLAYER:
    (Player*)otherObject->dealDamage(10);
    break;
case BULLETPROOF_GLASS:
    (BulletproofGlass*)otherObject->ricochet();
    break;
}

这样做:

otherObject->onHitByBullet(this);

这有时被称为tell, don't ask原则。

答案 1 :(得分:1)

这并非严格意义上的设计错误。虽然你当然可以从类型检查中抽象出类型。为了性能和运行时自定义,您几乎肯定不会使用RTTI或其他直接类型检查系统。实现自己的(简化的)类型检查动态允许对象在对象级别而不是类级别定义碰撞行为,并在运行时重新定义碰撞行为。

//PSEUDO CODE
enum CollisionTypes = {HARD_THING, SOFT_THING, EXPLODING_THING};

class FragileThing is a GameObject
{
    public function getCollisionType()
    {
        return SOFT_THING;
    }
    public function collideWith(GameObject obj)
    {
        if (obj.getCollisionType() == SOFT_THING)
            print "whew...";
        else
            print "OUCH!";
    }
}

class CollisionDispatcher is a PhysXCollisionListener
{
    public function getCollisionFromPhysX(Collision col)
    {
        col.left.collideWith(col.right);
        col.right.collideWith(col.left);
    }
}

我见过的另一个系统(书中使用)是使用引擎范围的消息传递框架来分配与嵌入到消息中的类型信息的冲突。不相关的类型可以简单地忽略消息。我没有试过这个。我还建议检查你的LevelObject类,以确定是否没有某种常见功能可以添加到它来避免这个问题。例如,如果基本类型的对象很少(可能是红色和绿色,或者是Ethereal,Soft,Hard,Explosive),那么您可以代替条件语句将这些类型编码为函数调用:function collideWithSomethingHard(LevelObject obj)从而允许对象只定义它们关心的碰撞行为。希望这有点帮助。

答案 2 :(得分:0)

如果您需要这样做,那么很可能您的界面缺乏或设计为次优。而是重新访问您的界面并提供一组适当的(可能是抽象的)虚拟方法来实现您所需的界面。然后你不必担心特定的子类型。

如果确实需要您可以使用typeid的信息,请参阅@Emil Styrke的答案

答案 3 :(得分:0)

使用函数typeid(pA).name()时。结果是class A *

// typeid
#include <iostream>
#include <typeinfo>
using namespace std;

class A
{
    public:
        A(){}
        virtual ~A(){}

    protected:

};

class B : public A
{
    public:
        B(){}
        virtual ~B(){}

    protected:

};


int main()
{
A* pA = new B();

   cout<<"The expression [A* pA = new B()]: \n";
   cout<<"Has datatype --> "<< typeid(pA).name()  <<"<-- \n";
   cout<<" \n";

   return 0;
}

输出:

The expression [A* pA = new B()]:
Has datatype --> class A *<--

Press any key to continue