Как узнать тип переменной с вовлеченным наследованием / полиморфизмом - PullRequest
0 голосов
/ 07 января 2012

Как узнать тип переменной, когда задействовано наследование?

У меня небольшая ситуация, я опишу ее в псевдокоде:

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?

Спасибо.


EDIT:

Я позволю вам судить, плохой дизайн или нет. Если вы думаете, что это так, то, пожалуйста, скажите мне лучшую альтернативу.

Код:

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 дает мне доступ к данным пользователя от актера, актер - это что-то из среды PhysX, которая определяет столкновения, физику и т. Д. Пользовательские данные имеют тип void*. Это также единственный способ узнать объект, которому на самом деле принадлежит актер.

Тогда есть class LevelElement, абстрактный класс, от которого наследуется каждый объект моего уровня (уровень как на уровне игры)

LevelElement имеет защищенные виртуальные методы: OnContactTouch(LevelElement* pOtherElement) и т. Д. В этих методах мне нужно выяснить, какой это тип LevelElement, чтобы принять определенные конкретные меры.

Это плохой дизайн? Если да, пожалуйста, помогите!

Ответы [ 4 ]

3 голосов
/ 07 января 2012

Используйте оператор 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.Прочтите этот вопрос , чтобы узнать, как с этим справиться.


РЕДАКТИРОВАТЬ: Что касается вашего вопроса о дизайне, то вместо проверки того, что является типом otherObject, лучшим решением будет просто сказатьэтот объект что делать.Предполагая, что вы хотите закодировать onContactTouch для гипотетического объекта Bullet;вместо

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

сделайте это:

otherObject->onHitByBullet(this);

Это иногда называют принципом скажи, не спрашивай .

1 голос
/ 07 января 2012

Это не строго признак плохого дизайна. Хотя вы, конечно, можете абстрагировать типы от проверки типов. Ради производительности и настройки времени выполнения вы почти наверняка НЕ ​​должны использовать 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), что позволяет объектам определить только поведение при столкновении Надеюсь, это немного поможет.

0 голосов
/ 07 января 2012

При использовании функции 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
0 голосов
/ 07 января 2012

Если вам нужно сделать это, то, скорее всего, ваш интерфейс отсутствует или разработан неоптимально. Вместо этого повторно посетите ваш интерфейс и предоставьте соответствующий набор (возможно, абстрактных) виртуальных методов для реализации необходимого интерфейса. Тогда вам не нужно беспокоиться о конкретных подтипах.

Если вам действительно нужна информация, которую вы можете использовать typeid, как видно из ответа @Emil Styrke

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...