Поиск типа объекта в С++

У меня есть класс A и другой класс, который наследует от него, B. Я переопределяю функцию, которая принимает объект типа A в качестве параметра, поэтому мне нужно принять A. Однако, я позже вызываю функции, которые только B имеет, поэтому я хочу вернуть false и не продолжать, если переданный объект не относится к типу B.

Каков наилучший способ узнать, какой тип объекта передал моей функции?

Ответ 1

dynamic_cast должен делать трюк

TYPE& dynamic_cast<TYPE&> (object);
TYPE* dynamic_cast<TYPE*> (object);

Ключевое слово dynamic_cast отбрасывает привязку из одного указателя или ссылочного типа в другой, выполняя проверку времени выполнения, чтобы гарантировать достоверность приведения.

Если вы попытаетесь наложить указатель на тип, который не является типом реального объекта, результат приведения будет NULL. Если вы попытаетесь применить для ссылки на тип, который не является типом фактического объекта, бросок будет генерировать исключение bad_cast.

Убедитесь, что в классе Base есть хотя бы одна виртуальная функция, чтобы сделать работу dynamic_cast.

Ответ 2

Динамическое литье является лучшим для описания проблемы, но я просто хочу добавить, что вы можете найти тип класса с помощью:

#include <typeinfo>

...
string s = typeid(YourClass).name()

Ответ 3

Это называется RTTI, но вы почти наверняка захотите пересмотреть свой дизайн здесь, потому что поиск типа и выполнение специальных действий на его основе делает ваш код более хрупким.

Ответ 4

Вероятно, вставляйте в свои объекты идентификатор "тег" и используйте его для различения объектов класса A и объектов класса B.

Это, однако, показывает недостаток в дизайне. В идеале те методы из B, которые A не имеют, должны быть частью A, но оставлены пустыми, а B их перезаписывает. Это устраняет код, специфичный для класса, и более соответствует духу ООП.

Ответ 5

Вы ищете dynamic_cast<B*>(pointer)

Ответ 6

Чтобы быть полным, я построю сборку Robocide и отметьте, что typeid можно использовать самостоятельно, не используя имя():

#include <typeinfo>
#include <iostream>

using namespace std;

class A {
public:
    virtual ~A() = default; // We're not polymorphic unless we
                            // have a virtual function.
};
class B : public A { } ;
class C : public A { } ;

int
main(int argc, char* argv[])
{
    B b;
    A& a = b;

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl;
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl;
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl;
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl;
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl;
}

Вывод:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false

Ответ 7

Как показали другие, вы можете использовать dynamic_cast. Но, как правило, использование dynamic_cast для определения типа производного класса, над которым вы работаете, указывает на плохой дизайн. Если вы переопределяете функцию, которая принимает указатель на A в качестве параметра, то она должна иметь возможность работать с методами/данными самого класса A и не должна зависеть от данных класса B. В вашем случае вместо переопределения, если вы что метод, который вы пишете, будет работать только с классом B, тогда вы должны написать новый метод в классе B.

Ответ 8

Потому что ваш класс не является полиморфным. Попробуйте:

struct BaseClas { int base; virtual ~BaseClas(){} };
class Derived1 : public BaseClas { int derived1; };

Теперь BaseClas является полиморфным. Я изменил класс на struct, потому что члены структуры являются общедоступными по умолчанию.

Ответ 9

Ваше описание немного запутанно.

Вообще говоря, хотя некоторые реализации С++ имеют механизмы для этого, вы не должны спрашивать о типе. Вместо этого вы должны сделать dynamic_cast на указателе на A. Что это будет делать, так это то, что во время выполнения будет проверено фактическое содержимое указателя на A. Если у вас есть B, вы получите свой указатель на B. В противном случае вы получите исключение или null.

Ответ 10

Используйте перегруженные функции. Не требует поддержки dynamic_cast или даже RTTI:

class A {};
class B : public A {};

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};

Ответ 11

Если вы можете получить доступ к библиотеке boost, возможно, функция type_id_with_cvr() - это то, что вам нужно, что может предоставить тип данных без удаления const, volatile и && & модификаторы. Вот простой пример в С++ 11:

#include <iostream>
#include <boost/type_index.hpp>

int a;
int& ff() 
{
    return a;
}

int main() {
    ff() = 10;
    using boost::typeindex::type_id_with_cvr;
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl;
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl;
    std::cout << typeid(ff()).name() << std::endl;
}

Надеюсь, это полезно.