Domanda

Stavo pensando di usare typeid() ma non so come chiedere se quel tipo è una sottoclasse di un'altra classe (che, a proposito, è astratta)

È stato utile?

Soluzione

Non dovresti davvero. Se il tuo programma ha bisogno di sapere che classe è un oggetto, questo di solito indica un difetto di progettazione. Verifica se riesci a ottenere il comportamento desiderato utilizzando le funzioni virtuali. Inoltre, sarebbero utili ulteriori informazioni su ciò che stai cercando di fare.

Suppongo che tu abbia una situazione come questa:

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

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

Se questo è quello che hai, prova a fare qualcosa del genere:

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();
}

Modifica: dato che il dibattito su questa risposta continua ancora dopo tanti anni, ho pensato di aggiungere alcuni riferimenti. Se hai un puntatore o un riferimento a una classe base e il tuo codice deve conoscere la classe derivata dell'oggetto, allora viola principio di sostituzione di Liskov . Zio Bob lo chiama un " anatema al design orientato agli oggetti " ;.

Altri suggerimenti

nbsp &;

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;
  }
}

Puoi farlo con dynamic_cast (almeno per i tipi polimorfici).

In realtà, ripensandoci - non puoi dire se È SPECIFICAMENTE un tipo particolare con <=> - ma puoi dire se è quel tipo o una sua sottoclasse.

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

dynamic_cast può determinare se il tipo contiene il tipo di destinazione in qualsiasi punto della gerarchia dell'ereditarietà (sì, è una funzione poco nota che se B eredita da A e C, può trasformare un <= > direttamente in A*). C* può determinare il tipo esatto dell'oggetto. Tuttavia, entrambi dovrebbero essere usati con estrema parsimonia. Come già accennato, dovresti sempre evitare l'identificazione dinamica del tipo, perché indica un difetto di progettazione. (inoltre, se sai che l'oggetto è sicuramente del tipo di destinazione, puoi eseguire un downcast con typeid(). Boost offre un static_cast che eseguirà un downcast con polymorphic_downcast e assert in modalità debug, e in modalità di rilascio utilizzerà solo un <=>).

Non sono d'accordo sul fatto che non si dovrebbe mai voler controllare il tipo di un oggetto in C ++. Se puoi evitarlo, sono d'accordo che dovresti. Dire che non dovresti MAI farlo in nessun caso va troppo lontano. Puoi farlo in molte lingue e può rendere la tua vita molto più semplice. Howard Pinsley, per esempio, ci ha mostrato come nel suo post su C #.

Lavoro molto con Qt Framework. In generale, modello quello che faccio dopo il modo in cui fanno le cose (almeno quando lavorano nel loro quadro). La classe QObject è la classe base di tutti gli oggetti Qt. Quella classe ha le funzioni isWidgetType () e isWindowType () come controllo rapido della sottoclasse. Quindi perché non essere in grado di controllare le proprie classi derivate, che è comparabile nella sua natura? Ecco uno spin off QObject di alcuni di questi altri post:

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 ); }
};

Quindi, quando si passa un puntatore a un oggetto QO, è possibile verificare se punta alla classe derivata chiamando la funzione membro statico:

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

Non so se capisco correttamente il tuo problema, quindi lasciami riaffermarlo con le mie stesse parole ...

Problema: date le classi B e D, determinare se TypeManip.h è una sottoclasse di SuperSubclass (o viceversa?)

Soluzione: usa un po 'di magia modello! Ok, sul serio devi dare un'occhiata a LOKI, un'eccellente libreria di meta-programmazione di modelli prodotta dal leggendario autore del C ++ Andrei Alexandrescu.

Più specificamente, scarica LOKI e includi l'intestazione < => da esso nel codice sorgente quindi utilizza il SuperSubClass<B,D>::value modello di classe come segue:

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

Secondo la documentazione, dynamic_cast sarà vero se <=> è una base pubblica di <=> o se <=> e <=> sono alias dello stesso tipo.

vale a dire. <=> è una sottoclasse di <=> o <=> è uguale a <=>.

Spero che questo aiuti.

modifica

Si noti che la valutazione di <=> avviene in fase di compilazione a differenza di alcuni metodi che utilizzano <=>, quindi non vi è alcuna penalità per l'utilizzo di questo sistema in fase di esecuzione.

#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;
  }
}

Risultato:

IS A D22
IS A D2
IS A Base

Puoi farlo solo in fase di compilazione usando i template, a meno che tu non usi RTTI.

Ti consente di utilizzare la funzione typeid che genererà un puntatore a una struttura type_info che contiene informazioni sul tipo.

Leggi su Wikipedia

In c # puoi semplicemente dire:

if (myObj is Car) {

}
  

Stavo pensando sulla falsariga di usare typeid() ...

Bene, sì, potrebbe essere fatto confrontando: typeid().name(). Se prendiamo la situazione già descritta, dove:

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

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

Una possibile implementazione di foo(Base *p) sarebbe:

#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
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top