Pergunta

Eu estava pensando ao longo das linhas de usar typeid() mas eu não sei como perguntar se esse tipo é uma subclasse de outra classe (que, por sinal, é abstrato)

Foi útil?

Solução

Você realmente não deveria. Se as suas necessidades de programa para saber o que classe um objeto é, que normalmente indica uma falha de projeto. Veja se você pode obter o comportamento desejado usando funções virtuais. Além disso, mais informações sobre o que você está tentando fazer ajudaria.

Eu estou supondo que você tem uma situação como esta:

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

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

Se é isso que você tem, em seguida, tentar fazer algo parecido com isto:

class Base
{
  virtual void bar() = 0;
};

class A : public Base
{
  void bar() {/* do X */}
};

class B : public Base
{
  void bar() {/* do Y */}
};

void foo(Base *p)
{
  p->bar();
}

Editar: Desde que o debate sobre esta resposta ainda continua depois de tantos anos, eu pensei que eu deveria jogar em algumas referências. Se você tem um ponteiro ou referência a uma classe base, e suas necessidades de código para saber a classe derivada do objeto, então ela viola Liskov princípio da substituição . Tio Bob chama isso de " anátema para Object Oriented design ".

Outras dicas

class Base
{
  public: virtual ~Base() {}
};

class D1: public Base {};

class D2: public Base {};

int main(int argc,char* argv[]);
{
  D1   d1;
  D2   d2;

  Base*  x = (argc > 2)?&d1:&d2;

  if (dynamic_cast<D2*>(x) == nullptr)
  {
    std::cout << "NOT A D2" << std::endl;
  }
  if (dynamic_cast<D1*>(x) == nullptr)
  {
    std::cout << "NOT A D1" << std::endl;
  }
}

Você pode fazê-lo com dynamic_cast (pelo menos para os tipos polimórficos).

Na verdade, pensando bem - você não pode dizer se é especificamente um tipo particular com dynamic_cast -. Mas você pode dizer se é que tipo ou qualquer subclasse do mesmo

template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
  return dynamic_cast<const DstType*>(src) != nullptr;
}

dynamic_cast pode determinar se o tipo contém a qualquer tipo de destino na hierarquia de herança (sim, é um recurso conhecido-pouco que se herda B de A e C, ele pode virar um A* diretamente em um C*). typeid() pode determinar o tipo exato do objeto. No entanto, estes devem tanto ser usado extremamente moderação. Como já foi mencionado, você deve sempre estar evitando identificação do tipo de dinâmica, porque indica uma falha de projeto. (Também, se você sabe o objeto é a certeza do tipo de destino, você pode fazer um abatido com um static_cast. Impulso oferece um polymorphic_downcast que vai fazer um abatido com dynamic_cast e assert no modo de depuração, e no modo de versão será apenas o uso um static_cast).

Eu discordo que você nunca deve querer verificar um tipo de objeto em C ++. Se você pode evitá-lo, eu concordo que você deve. Dizendo que você nunca deve fazer isso em qualquer circunstância está indo longe demais embora. Você pode fazer isso em um grande número de línguas, e pode tornar sua vida muito mais fácil. Howard Pinsley, por exemplo, mostrou-nos como em seu post sobre C #.

Eu faço um monte de trabalho com o framework Qt. Em geral, eu modelar o que eu faço depois da maneira como eles fazem as coisas (pelo menos quando se trabalha em seu quadro). A classe QObject é a classe base de todos os objetos do Qt. Essa classe tem a funções isWidgetType () e isWindowType () como um cheque subclasse rápido. Então por que não ser capaz de verificar suas próprias classes derivadas, o que é comparável em sua natureza? Aqui é um spin off QObject de algumas dessas outras mensagens:

class MyQObject : public QObject
{
public:
    MyQObject( QObject *parent = 0 ) : QObject( parent ){}
    ~MyQObject(){}

    static bool isThisType( const QObject *qObj )
    { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); }
};

E então, quando você está passando em torno de um ponteiro para um QObject, você pode verificar se ele aponta para sua classe derivada chamando a função de membro estático:

if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";

Eu não sei se eu entendi o seu problema corretamente, então deixe-me reformular isso na minha próprias palavras ...

Problema: (ou vice-versa) Dada aulas B e D, determinar se D é uma subclasse de B

Solução: Use um pouco de magia template! Ok, seriamente você precisa dar uma olhada em LOKI, uma biblioteca de meta-programação excelente modelo produzido pelo autor lendário C ++ Andrei Alexandrescu.

Mais especificamente, baixar LOKI e incluem TypeManip.h cabeçalho com isso em seu código-fonte, em seguida, usar o modelo de classe SuperSubclass da seguinte forma:

if(SuperSubClass<B,D>::value)
{
...
}

De acordo com a documentação, SuperSubClass<B,D>::value será verdadeira se B é uma base pública de D, ou se B e D são pseudônimos do mesmo tipo.

i. quer D é uma subclasse de B ou D é o mesmo que B.

Espero que isso ajude.

Editar:

Por favor, note a avaliação de SuperSubClass<B,D>::value acontece em tempo de compilação ao contrário de alguns métodos que dynamic_cast uso, portanto, não há nenhuma penalidade para a utilização deste sistema em tempo de execução.

#include <stdio.h>
#include <iostream.h>

class Base
{
  public: virtual ~Base() {}

  template<typename T>
  bool isA() {
    return (dynamic_cast<T*>(this) != NULL);
  }
};

class D1: public Base {};
class D2: public Base {};
class D22: public D2 {};

int main(int argc,char* argv[]);
{
  D1*   d1  = new D1();
  D2*   d2  = new D2();
  D22*  d22 = new D22();

  Base*  x = d22;

  if( x->isA<D22>() )
  {
    std::cout << "IS A D22" << std::endl;
  }
  if( x->isA<D2>() )
  {
    std::cout << "IS A D2" << std::endl;
  }
  if( x->isA<D1>() )
  {
    std::cout << "IS A D1" << std::endl;
  }
  if(x->isA<Base>() )
  {
    std::cout << "IS A Base" << std::endl;
  }
}

Resultado:

IS A D22
IS A D2
IS A Base

Você só pode fazê-lo em tempo de compilação usando modelos, a menos que você usar RTTI.

Ele permite que você use a função typeid que permitirá obter um ponteiro para uma estrutura type_info que contém informações sobre o tipo.

Leia-se sobre ele em Wikipedia

Em c #, você pode simplesmente dizer:

if (myObj is Car) {

}

Eu estava pensando ao longo das linhas de usar typeid() ...

Bem, sim, isso poderia ser feito através da comparação: typeid().name(). Se tomarmos a situação já descrita, em que:

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

void foo(Base *p)
{
  if(/* p is A */) /* do X */
  else /* do Y */
}

Uma possível implementação de foo(Base *p) seria:

#include <typeinfo>

void foo(Base *p)
{
    if(typeid(*p) == typeid(A))
    {
        // the pointer is pointing to the derived class A
    }  
    else if (typeid(*p).name() == typeid(B).name()) 
    {
        // the pointer is pointing to the derived class B
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top