Нахождение типа объекта в C ++ - PullRequest
130 голосов
/ 09 декабря 2008

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

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

Ответы [ 11 ]

142 голосов
/ 09 декабря 2008

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

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

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

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

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

134 голосов
/ 01 декабря 2010

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

#include <typeinfo>

...
string s = typeid(YourClass).name()
23 голосов
/ 09 декабря 2008

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

9 голосов
/ 09 декабря 2008

Вероятно, встраивайте в ваши объекты идентификатор «тег» и используйте его для различения объектов класса А и объектов класса В.

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

7 голосов
/ 31 марта 2016

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

#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 голосов
/ 09 декабря 2008

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

3 голосов
/ 27 января 2011

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

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

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

3 голосов
/ 09 декабря 2008

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

2 голосов
/ 09 декабря 2008

Ваше описание немного сбивает с толку.

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

1 голос
/ 04 декабря 2017

Если вы можете получить доступ к библиотеке надстройки, возможно, вам нужна функция type_id_with_cvr () , которая может предоставить тип данных без удаления const volatile, & и && модификаторы . Вот простой пример в C ++ 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;
}

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

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