web-dev-qa-db-fra.com

Comment puis-je obtenir le nom de la classe à partir d'un objet C ++?

Est-il possible d'obtenir le nom de l'objet aussi?

#include<cstdio>

class one {
public:
    int no_of_students;
    one() { no_of_students = 0; }
    void new_admission() { no_of_students++; }
};

int main() {
    one A;
    for(int i = 0; i < 99; i++) {
        A.new_admission();
    }
    cout<<"class"<<[classname]<<" "<<[objectname]<<"has "
        <<A.no_of_students<<" students";
}

où je peux aller chercher les noms, quelque chose comme

[classname] = A.classname() = one
[objectname] = A.objectname() = A

C++ fournit-il un mécanisme pour y parvenir?

44
Lazer

Vous pouvez afficher le nom d'une variable à l'aide du préprocesseur. Par exemple

#include <iostream>
#define quote(x) #x
class one {};
int main(){
    one A;
    std::cout<<typeid(A).name()<<"\t"<< quote(A) <<"\n";
    return 0;
}

les sorties

3one    A

sur ma machine. Le # transforme un jeton en chaîne. Après le prétraitement de la ligne,

std::cout<<typeid(A).name()<<"\t"<< "A" <<"\n";

Bien sûr si vous faites quelque chose comme

void foo(one B){
    std::cout<<typeid(B).name()<<"\t"<< quote(B) <<"\n";
}
int main(){
    one A;
    foo(A);
    return 0;
}

tu auras

3one B

comme le compilateur ne garde pas trace de tous les noms de la variable.

Comme dans gcc, le résultat de typeid (). Name () est le nom de la classe mutilé, pour obtenir le version démêlée use

#include <iostream>
#include <cxxabi.h>
#define quote(x) #x
template <typename foo,typename bar> class one{ };
int main(){
    one<int,one<double, int> > A;
    int status;
    char * demangled = abi::__cxa_demangle(typeid(A).name(),0,0,&status);
    std::cout<<demangled<<"\t"<< quote(A) <<"\n";
    free(demangled);
    return 0;
}

ce qui me donne

one<int, one<double, int> > A

D'autres compilateurs peuvent utiliser des schémas de nommage différents.

67
Scott Wales

utiliser typeid(class).name

// code illustratif supposant tous les inclus/espaces de noms, etc.

#include <iostream>
#include <typeinfo>
using namespace std;

struct A{};
int main(){
   cout << typeid(A).name();
}

Il est important de se rappeler que cela donne à une implémentation des noms définis.

Pour autant que je sache, il n'existe aucun moyen d'obtenir le nom de l'objet au moment de l'exécution de manière fiable, par exemple. "A" dans votre code.

EDIT 2:

#include <typeinfo>
#include <iostream>
#include <map>
using namespace std; 

struct A{
};
struct B{
};

map<const type_info*, string> m;

int main(){
    m[&typeid(A)] = "A";         // Registration here
    m[&typeid(B)] = "B";         // Registration here

    A a;
    cout << m[&typeid(a)];
}
18
Chubsdad

Pour obtenir le nom de classe sans complication, vous pouvez utiliser la macro func du constructeur:

class MyClass {
    const char* name;
    MyClass() {
        name = __func__;
    }
}
9
grungegurunge

Voulez-vous que [nom de classe] soit "un" et que [nom d'objet] soit "A"?

Si c'est le cas, ce n'est pas possible. Ces noms ne sont que des abstractions pour le programmeur et ne sont pas réellement utilisés dans le code binaire généré. Vous pouvez attribuer à la classe un nom de classe variable statique, défini à "un", et un nom de variable normal, que vous affecteriez directement, via une méthode ou le constructeur. Vous pouvez ensuite interroger ces méthodes pour connaître les noms de classe et d'objet.

8
Alexander Rafferty

Il suffit d'écrire un modèle simple:

template<typename T>
const char* getClassName(T) {
  return typeid(T).name();
}

struct A {} a;

void main() {
   std::cout << getClassName(a);
}
4
sea-kg

Vous pouvez essayer d'utiliser "typeid" .

Cela ne fonctionne pas pour le nom d'objet, mais vous connaissez le nom de l'objet, vous devez donc le stocker quelque part. Le compilateur ne se soucie pas de ce que vous avez nommé un objet.

Il est bon de garder à l’esprit, cependant, que la sortie de typeid est une chose spécifique au compilateur, donc même si elle produit ce que vous recherchez sur la plate-forme actuelle, elle ne le sera peut-être pas sur une autre. Cela peut ou peut ne pas être un problème pour vous.

L’autre solution consiste à créer une sorte d’emballage de modèle dans lequel vous stockez le nom de la classe. Vous devez ensuite utiliser une spécialisation partielle pour l’obtenir afin de vous renvoyer le nom de classe correct. Cela a l’avantage de travailler le temps de compilation mais est beaucoup plus complexe.

Edit: être plus explicite

template< typename Type > class ClassName
{
public:
    static std::string name()
    {
        return "Unknown";
    }
};

Alors, pour chaque classe, quelque chose se passe comme suit:

template<> class ClassName<MyClass>
{
public:
    static std::string name()
    {
        return "MyClass";
    }
};

Ce qui pourrait même être une macro comme suit:

#define DefineClassName( className ) \
\
template<> class ClassName<className> \
{ \
public: \
    static std::string name() \
    { \
        return #className; \
    } \
}; \

Vous permettant de faire simplement

DefineClassName( MyClass );

Enfin, pour obtenir le nom de la classe, procédez comme suit:

ClassName< MyClass >::name();

Edit2: En approfondissant vous devez ensuite mettre cette macro "DefineClassName" dans chaque classe que vous faites et définir une fonction "classname" qui appellerait la fonction de modèle statique.

Edit3: Et y penser ... C'est évidemment mauvais de poster dès le matin car vous pouvez aussi bien définir une fonction membre "classname ()" comme suit:

std::string classname()
{
     return "MyClass";
}

qui peut être macro comme suit:

DefineClassName( className ) \
std::string classname()  \
{ \
     return #className; \
}

Ensuite, vous pouvez simplement laisser tomber

DefineClassName( MyClass );

dans la classe comme vous le définissez ...

4
Goz

Une amélioration pour @Chubsdad answer,

//main.cpp

using namespace std;

int main(){
A a;
a.run();
}

//A.h
class A{
public:
 A(){};
 void run();
}

//A.cpp
#include <iostream>
#include <typeinfo>
void A::run(){
   cout << (string)typeid(this).name();
}

Qui va imprimer:

class A*
2
OhadM