How can I get the class name from a C++ object?

前端 未结 8 2123
名媛妹妹
名媛妹妹 2020-11-29 20:56

Is it possible to get the object name too?

#include

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


        
相关标签:
8条回答
  • 2020-11-29 21:24

    Do you want [classname] to be 'one' and [objectname] to be 'A'?

    If so, this is not possible. These names are only abstractions for the programmer, and aren't actually used in the binary code that is generated. You could give the class a static variable classname, which you set to 'one' and a normal variable objectname which you would assign either directly, through a method or the constructor. You can then query these methods for the class and object names.

    0 讨论(0)
  • 2020-11-29 21:25

    An improvement for @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();
    }
    

    Which will print:

    class A*
    
    0 讨论(0)
  • 2020-11-29 21:26

    You can try this:

    template<typename T>
    inline const char* getTypeName() {
      return typeid(T).name();
    }
    
    #define DEFINE_TYPE_NAME(type, type_name)  \
      template<>                               \
      inline const char* getTypeName<type>() { \
        return type_name;                      \
      }
    
    DEFINE_TYPE_NAME(int, "int")
    DEFINE_TYPE_NAME(float, "float")
    DEFINE_TYPE_NAME(double, "double")
    DEFINE_TYPE_NAME(std::string, "string")
    DEFINE_TYPE_NAME(bool, "bool")
    DEFINE_TYPE_NAME(uint32_t, "uint")
    DEFINE_TYPE_NAME(uint64_t, "uint")
    // add your custom types' definitions
    

    And call it like that:

    void main() {
     std::cout << getTypeName<int>();
    }
    
    0 讨论(0)
  • 2020-11-29 21:29

    You can display the name of a variable by using the preprocessor. For instance

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

    outputs

    3one    A
    

    on my machine. The # changes a token into a string, after preprocessing the line is

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

    Of course if you do something like

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

    you will get

    3one B
    

    as the compiler doesn't keep track of all of the variable's names.

    As it happens in gcc the result of typeid().name() is the mangled class name, to get the demangled version 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;
    }
    

    which gives me

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

    Other compilers may use different naming schemes.

    0 讨论(0)
  • 2020-11-29 21:31

    To get class name without mangling stuff you can use func macro in constructor:

    class MyClass {
        const char* name;
        MyClass() {
            name = __func__;
        }
    }
    
    0 讨论(0)
  • 2020-11-29 21:34

    You could try using "typeid".

    This doesn't work for "object" name but YOU know the object name so you'll just have to store it somewhere. The Compiler doesn't care what you namned an object.

    Its worth bearing in mind, though, that the output of typeid is a compiler specific thing so even if it produces what you are after on the current platform it may not on another. This may or may not be a problem for you.

    The other solution is to create some kind of template wrapper that you store the class name in. Then you need to use partial specialisation to get it to return the correct class name for you. This has the advantage of working compile time but is significantly more complex.

    Edit: Being more explicit

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

    Then for each class somethign liek the following:

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

    Which could even be macro'd as follows:

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

    Allowing you to, simply, do

    DefineClassName( MyClass );
    

    Finally to Get the class name you'd do the following:

    ClassName< MyClass >::name();
    

    Edit2: Elaborating further you'd then need to put this "DefineClassName" macro in each class you make and define a "classname" function that would call the static template function.

    Edit3: And thinking about it ... Its obviously bad posting first thing in the morning as you may as well just define a member function "classname()" as follows:

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

    which can be macro'd as follows:

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

    Then you can simply just drop

    DefineClassName( MyClass );
    

    into the class as you define it ...

    0 讨论(0)
提交回复
热议问题