web-dev-qa-db-fra.com

Trouver le type d'un objet en C++

J'ai une classe A et une autre classe qui en hérite, B. Je remplace une fonction qui accepte un objet de type A en tant que paramètre. Je dois donc accepter un A. Cependant, j'appellerai plus tard des fonctions que seul B a donc je veux retourner false et ne pas continuer si l'objet transmis n'est pas de type B.

Quel est le meilleur moyen de savoir quel type d'objet est transmis à ma fonction?

128
lemnisca

dynamic_cast devrait faire l'affaire 

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

Le mot clé dynamic_cast transfère une donnée d'un pointeur ou d'un type de référence à un autre, en effectuant une vérification à l'exécution pour s'assurer de la validité de la conversion.

Si vous essayez de transtyper un pointeur sur un type qui n'est pas un type d'objet réel, le résultat de la transposition sera NULL. Si vous essayez de faire référence à un type qui n'est pas un type d'objet réel, la conversion lève une exception bad_cast .

Assurez-vous qu'il y a au moins une fonction virtuelle dans la classe de base pour que dynamic_cast fonctionne.

141
yesraaj

La conversion dynamique convient le mieux à votre description du problème, .__, mais je tiens simplement à ajouter que vous pouvez trouver le type de classe avec:

#include <typeinfo>

...
string s = typeid(YourClass).name()
130
Robocide

Ceci s'appelle RTTI , mais vous voudrez sûrement reconsidérer votre conception ici, car le fait de rechercher le type et de faire des opérations spéciales en conséquence rend votre code plus fragile.

23
Paul Betts

Intégrez probablement dans vos objets un "tag" ID et utilisez-le pour distinguer les objets de classe A des objets de classe B.

Cela montre cependant une faille dans la conception. Idéalement, les méthodes de B que A n’a pas doivent faire partie de A mais doivent rester vides et B les écrase. Cela supprime le code spécifique à la classe et correspond davantage à l'esprit de la programmation orientée objet. 

9
freespace

Recherchez-vous dynamic_cast<B*>(pointer)?

7
Joshua

Pour être complet, je vais construire à partir de Robocide et souligner que typeid peut être utilisé seul sans utiliser 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;
}

Sortie:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false
6
firebush

Parce que votre classe n'est pas polymorphe. Essayer:

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

Maintenant, BaseClas est polymorphe. J'ai changé de classe en struct car les membres d'une structure sont publics par défaut.

3
c64zottel

Comme d'autres l'ont indiqué, vous pouvez utiliser dynamic_cast. Mais en règle générale, utiliser dynamic_cast pour déterminer le type de la classe dérivée sur laquelle vous travaillez indique la mauvaise conception. Si vous substituez une fonction qui prend le pointeur de A comme paramètre, vous devriez pouvoir utiliser les méthodes/données de la classe A elle-même et ne pas dépendre des données de la classe B. êtes sûr que la méthode que vous écrivez ne fonctionnera qu'avec la classe B, vous devriez alors écrire une nouvelle méthode dans la classe B.

3
Naveen

Votre description est un peu déroutant. 

De manière générale, bien que certaines implémentations C++ disposent de mécanismes, vous n'êtes pas censé poser de questions sur le type. Au lieu de cela, vous êtes censé faire un dynamic_cast sur le pointeur sur A. Cela permettra de vérifier que, lors de l'exécution, le contenu du pointeur sur A sera vérifié. Si vous avez un B, vous obtiendrez votre pointeur sur B. Sinon, vous obtiendrez une exception ou une valeur nulle.

2
Uri

Utilisez des fonctions surchargées. Ne nécessite pas le support dynamic_cast ou même RTTI:

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

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};
1
jmucchiello

Si vous pouvez accéder à la bibliothèque boost, vous pouvez éventuellement utiliser la fonction type_id_with_cvr (), qui peut fournir le type de données sans supprimer modificateurs const, volatile et & && . Voici un exemple simple en 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;
}

J'espère que c'est utile.

0
Kehe CAI