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)
Tu ne devrais 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 que vous souhaitez en utilisant des fonctions virtuelles. En outre, il serait utile d’avoir plus d’informations sur ce que vous essayez de faire.
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();
}
Edit: Etant donné que le débat sur cette réponse continue après des années, je me suis dit que je devrais 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 le principe de substitution de Liskov . Oncle Bob appelle cela un " anathème à la conception orientée objet ".
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 dynamic_cast
-- mais vous pouvez savoir 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
, elle peut transformer un A*
directement en un C*
). typeid()
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 static_cast
. Boost propose un polymorphic_downcast
qui effectuera un downcast avec dynamic_cast
et assert
en mode débogage et en mode de publication, il utilisera simplement un static_cast
).
Je ne sais pas si je comprends votre problème correctement, alors laissez-moi le reformuler avec mes propres mots ...
Problème: Étant donné les classes B
et D
, déterminez si D
est une sous-classe de B
(ou vice-versa?)
Solution: Utilisez des modèles de magie! Sérieusement, vous devez jeter un coup d’œil à LOKI, une excellente bibliothèque de méta-programmation pour modèles produite par le célèbre auteur C++, Andrei Alexandrescu.
Plus précisément, téléchargez LOKI et incluez l'en-tête TypeManip.h
dans votre code source, puis utilisez le modèle de classe SuperSubclass
comme suit:
if(SuperSubClass<B,D>::value)
{
...
}
Selon la documentation, SuperSubClass<B,D>::value
sera vrai si B
est une base publique de D
ou si B
et D
sont des alias du même type.
c'est-à-dire que D
est une sous-classe de B
ou D
est identique à B
.
J'espère que ça aide.
modifier:
Veuillez noter que l'évaluation de SuperSubClass<B,D>::value
se produit à la compilation contrairement à certaines méthodes qui utilisent dynamic_cast
, il n'y a donc aucune pénalité pour l'utilisation de ce système au moment de l'exécution.
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 façon 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, ce qui est comparable dans sa 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 ); }
};
Et 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!";
En c #, vous pouvez simplement dire:
if (myObj is Car) {
}
#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.
Lisez à ce sujet sur Wikipedia
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
}
}
Le code ci-dessous illustre 3 manières différentes de le faire:
#include <iostream>
#include <typeinfo>
#include <typeindex>
enum class Type {Base, A, B};
class Base {
public:
virtual ~Base() = default;
virtual Type type() const {
return Type::Base;
}
};
class A : public Base {
Type type() const override {
return Type::A;
}
};
class B : public Base {
Type type() const override {
return Type::B;
}
};
int main()
{
const char *typemsg;
A a;
B b;
Base *base = &a; // = &b; !!!!!!!!!!!!!!!!!
Base &bbb = *base;
// below you can replace base with &bbb and get the same results
// USING virtual function
// ======================
// classes need to be in your control
switch(base->type()) {
case Type::A:
typemsg = "type A";
break;
case Type::B:
typemsg = "type B";
break;
default:
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
// USING typeid
// ======================
// needs RTTI. under gcc, avoid -fno-rtti
std::type_index ti(typeid(*base));
if (ti == std::type_index(typeid(A))) {
typemsg = "type A";
} else if (ti == std::type_index(typeid(B))) {
typemsg = "type B";
} else {
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
// USING dynamic_cast
// ======================
// needs RTTI. under gcc, avoid -fno-rtti
if (dynamic_cast</*const*/ A*>(base)) {
typemsg = "type A";
} else if (dynamic_cast</*const*/ B*>(base)) {
typemsg = "type B";
} else {
typemsg = "unknown";
}
std::cout << typemsg << std::endl;
}
Le programme ci-dessus affiche ceci:
type A
type A
type A