如何找出变量的类型,包括继承/多态性

How to find out the type of a variable, with inheritance/polymorphism involved

本文关键字:包括 继承 多态性 类型 何找出 变量      更新时间:2023-10-16

当涉及继承时,如何找出变量的类型?

我有一个小情况,我将用伪代码描述:

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允许我从actor访问userData,actor是PhysX框架的一部分,用于确定碰撞和物理等。用户数据的类型为void*。这也是找出行动者实际所属对象的唯一方法

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

LevelElement具有受保护的虚拟方法:OnContactTouch(LevelElement* pOtherElement)等。。。在这些方法中,我需要弄清楚它是什么类型的LevelElement,以采取某些具体措施。

这个设计不好吗?如果是,请帮忙!

使用typeid运算符,例如此处所述。

基本上:

#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时会有一些混乱。看看这个问题,了解如何处理这个问题。


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

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

这样做:

otherObject->onHitByBullet(this);

这有时被称为"告诉,不要问"原则。

严格来说,这并不是糟糕设计的症状。尽管您当然可以从类型检查中抽象出类型。为了性能和运行时自定义,您几乎绝对不应该使用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类,以确定是否没有可以添加到其中的某种通用功能来避免这个问题。例如,如果对象的基本类型很少(可能是红色和绿色,或者以太、软、硬、爆炸),那么您可以将这些类型编码为函数调用,而不是条件语句:function collideWithSomethingHard(LevelObject obj),从而允许对象只定义它们关心的碰撞行为。希望这能有所帮助。

如果您需要这样做,那么很可能您的接口缺乏或设计得不够理想。相反,重新访问您的接口,并提供一组适当的(可能是抽象的)虚拟方法来实现所需的接口。那么你就不需要担心特定的子类型了。

如果您真的需要信息,您可以使用typeid,如@Emil Styrke 的答案所示

使用函数typeid(pA).name()时。结果是CCD_ 8。

// 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