Question

Je pensais utiliser typeid() mais je ne sais pas comment demander si ce type est une sous-classe d'une autre classe (ce qui est d'ailleurs abstrait)

Était-ce utile?

La solution

Vous ne devriez vraiment pas. Si votre programme a besoin de savoir quelle classe est un objet, cela indique généralement un défaut de conception. Voyez si vous pouvez obtenir le comportement souhaité à l'aide de fonctions virtuelles. De plus, plus d’informations sur ce que vous essayez de faire vous aideraient.

Je suppose que vous avez une situation comme celle-ci:

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

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

Si c'est ce que vous avez, essayez de faire quelque chose comme ceci:

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

Modifier: Étant donné que le débat autour de cette réponse se poursuit après tant d'années, j'ai pensé devoir ajouter quelques références. Si vous avez un pointeur ou une référence à une classe de base et que votre code doit connaître la classe dérivée de l'objet, il enfreint Principe de substitution de Liskov . Oncle Bob appelle cela un & "; anathème pour la conception orientée objet &";

Autres conseils

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

Vous pouvez le faire avec dynamic_cast (au moins pour les types polymorphes).

En fait, à bien y penser - vous ne pouvez pas savoir s'il s'agit spécifiquement d'un type particulier avec <=> - mais vous pouvez indiquer s'il s'agit de ce type ou de l'une de ses sous-classes.

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

dynamic_cast peut déterminer si le type contient le type cible n'importe où dans la hiérarchie d'héritage (oui, il s'agit d'une fonctionnalité peu connue qui, si B hérite de A et C, il peut transformer un <= > directement dans un A*). C* peut déterminer le type exact de l'objet. Cependant, ils doivent tous deux être utilisés avec beaucoup de parcimonie. Comme cela a déjà été mentionné, vous devriez toujours éviter l'identification de type dynamique, car elle indique un défaut de conception. (De plus, si vous savez que l'objet est sûr du type de cible, vous pouvez effectuer un downcast avec un typeid(). Boost propose un static_cast qui effectuera un downcast avec polymorphic_downcast et assert en mode débogage, et en mode release, il utilisera simplement un <=>).

Je ne suis pas d'accord pour dire que vous ne devriez jamais vouloir vérifier le type d'un objet en C ++. Si vous pouvez l'éviter, je conviens que vous devriez le faire. Dire que vous ne devriez JAMAIS faire cela en toutes circonstances va cependant trop loin. Vous pouvez le faire dans de très nombreuses langues et vous faciliter la vie beaucoup plus facilement. Howard Pinsley, par exemple, nous a montré comment dans son post sur C #.

Je travaille beaucoup avec Qt Framework. En général, je modélise ce que je fais après la manière dont ils font les choses (du moins lorsque je travaille dans leur cadre). La classe QObject est la classe de base de tous les objets Qt. Cette classe a les fonctions isWidgetType () et isWindowType () en tant que vérification rapide de sous-classe. Alors, pourquoi ne pas pouvoir vérifier vos propres classes dérivées, qui sont comparables dans leur nature? Voici un extrait de QObject de certains de ces autres articles:

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

Ensuite, lorsque vous passez un pointeur sur un QObject, vous pouvez vérifier s'il pointe vers votre classe dérivée en appelant la fonction membre static:

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

Je ne sais pas si j'ai bien compris votre problème, laissez-moi le reformuler avec mes propres mots ...

Problème: à partir des classes B et D, déterminez si TypeManip.h est une sous-classe de SuperSubclass (ou inversement?)

Solution: Utilisez des modèles de magie! Sérieusement, vous devez jeter un coup d’œil à LOKI, une excellente librairie de méta-programmation produite par le célèbre auteur C ++, Andrei Alexandrescu.

Plus précisément, téléchargez LOKI et incluez l'en-tête < => dans votre code source, utilisez le SuperSubClass<B,D>::value modèle de classe comme suit:

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

Selon la documentation, dynamic_cast sera vrai si <=> est une base publique de <=>, ou si <=> et <=> sont des alias du même type.

i.e. soit <=> est une sous-classe de <=> ou <=> est identique à <=>.

J'espère que cela vous aidera.

modifier:

Veuillez noter que l'évaluation de <=> se produit à la compilation contrairement à certaines méthodes qui utilisent <=>. Il n'y a donc aucune pénalité pour l'utilisation de ce système à l'exécution.

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

Résultat:

IS A D22
IS A D2
IS A Base

Vous ne pouvez le faire qu'au moment de la compilation à l'aide de modèles, sauf si vous utilisez RTTI.

Il vous permet d'utiliser la fonction typeid qui donnera un pointeur sur une structure type_info contenant des informations sur le type.

Consultez-la sur Wikipedia

En c #, vous pouvez simplement dire:

if (myObj is Car) {

}
  

Je pensais utiliser typeid() ...

Eh bien, oui, cela pourrait être fait en comparant: typeid().name(). Si nous prenons la situation déjà décrite, où:

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

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

Une implémentation possible de foo(Base *p) serait:

#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
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top