Приведение типов в С++ путем обнаружения текущего типа объекта "этот"

Мой вопрос связан с RTTI в С++, где я пытаюсь проверить, принадлежит ли объект иерархии типов другого объекта. Метод BelongsTo() проверяет это. Я пытался использовать typeid, но он выдает ошибку, и я не знаю, как найти целевой тип для преобразования во время выполнения.

#include <iostream>
#include <typeinfo>

class X
{
    public:
        //  Checks if the input type belongs to the type heirarchy of input object type
        bool BelongsTo(X* p_a)
        {
            //  I'm trying to check if the current (this) type belongs to the same type 
            //  hierarchy as the input type
            return dynamic_cast<typeid(*p_a)*>(this) != NULL;   //  error C2059: syntax error 'typeid'
        }
};

class A : public X
{
};

class B : public A
{
};

class C : public A
{
};

int main()
{
    X* a = new A();
    X* b = new B();
    X* c = new C();
    bool test1 = b->BelongsTo(a);   // should return true
    bool test2 = b->BelongsTo(c);   // should return false
    bool test3 = c->BelongsTo(a);   // should return true
}

Делать метод виртуальным и позволять производным классам делать это кажется плохой идеей, поскольку у меня много классов в иерархии одного и того же типа. Или кто-нибудь знает какой-либо другой/лучший способ сделать то же самое? Пожалуйста, предложите.

Обновление: b.BelongsTo(a) должен определять, является ли тип входного объекта (a) предком текущего объекта (b) в иерархии типов.


person Community    schedule 02.06.2010    source источник
comment
Хотя я не уверен, что это можно сделать правильно, я также не знаю, как это может быть полезным. Просто из любопытства, почему вы хотите этого добиться?   -  person ereOn    schedule 02.06.2010
comment
См., например, комментарии к ответу Нила.   -  person Elroy    schedule 02.06.2010
comment
Например. C происходит от B, происходит от A, X происходит от A. В некоторых случаях мне может потребоваться проверить, что тип объекта, который я получаю, на который указывает указатель базового класса (A*), должен быть типа B, а не типа X, если что я выкину ошибку.   -  person Elroy    schedule 02.06.2010


Ответы (2)


Это не имеет смысла — сам факт того, что вы можете вызвать функцию, означает, что параметр принадлежит к иерархии X, поскольку это тип параметра. Динамические приведения предназначены для определения фактического типа в пределах известной иерархии.

Синтаксическая ошибка в вашем коде:

return dynamic_cast<typeid(*p_a)*>(this) != NULL;  

это потому, что typeid не является типом - вы просто не можете использовать его как тип с таким dynamic_cast.

Если, как предлагает Навин, вы хотите узнать, принадлежит ли экземпляр к подиерархии, используйте:

if ( dynamic_cast <A*>( some_x_ptr ) ) {

    // yes, belongs to A sub-hierarchy
}

Изменить: у вас есть:

A <- P <- X
A <- Q <- Y

Затем:

A * a = new X;

dynamic_cast <P *>( a );   // not null
dynamic_cast <Q *>( a );   // null
person Community    schedule 02.06.2010
comment
Обратите внимание, что class B и class C являются производными от class A. Я думаю, что цель ОП состоит в том, чтобы выяснить, принадлежат ли переданные объекты к этой подиерархии или нет. - person Naveen; 02.06.2010
comment
Прошу прощения за то, что не совсем ясно выразился здесь. Например. X происходит от P, Y происходит от Q, где P и Q происходят от A. Итак, X принадлежит P и A, Y принадлежит Q и A, но X не принадлежит Q. Мне нужно такое поведение. - person Elroy; 02.06.2010
comment
Я не уверен, есть ли название для такого обнаружения, но это похоже на проверку предков. - person Elroy; 02.06.2010
comment
Круто, теперь, как вы думаете, как это вписывается в код, который я написал. Если вы попробуете это, может быть, вы получите лучшее представление о том, что я пытаюсь сделать. Какие изменения в BelongsTo() потребуются? - person Elroy; 02.06.2010
comment
@Elroy Вы не можете написать это как обычную функцию, потому что вещь в угловых скобках должна быть известна во время компиляции. Вы могли бы написать это как шаблон (я думаю). - person ; 02.06.2010
comment
Хорошо. Лучшее решение — сделать его виртуальным и обеспечить реализацию во всех подклассах, верно? - person Elroy; 02.06.2010
comment
@Elroy Нет, лучшее решение - просто использовать dynamic_cast, который делает именно то, что вы хотите. - person ; 02.06.2010

Чтобы RTTI работал, class X требуется хотя бы одна виртуальная функция-член (также учитывается виртуальный деструктор). Без виртуальных функций-членов у класса не будет виртуальной таблицы, сгенерированной компилятором, и поэтому, когда вы вызываете typeid, последний не будет работать так, как вы ожидаете.

person sharptooth    schedule 02.06.2010
comment
Я добавил виртуальный деструктор в каждый класс. Но он все еще показывает эту синтаксическую ошибку. Любые идеи? - person Elroy; 02.06.2010
comment
Да, см. ответ Нила Баттерворта. - person sharptooth; 02.06.2010