如何从c++对象获取类名?

时间:2022-09-06 08:33:30

Is it possible to get the object name too?

是否也可以获得对象名?

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

where I can fetch the names, something like

我可以在哪里取名字,比如?

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

Does C++ provide any mechanism to achieve this?

c++提供了实现这一目标的机制吗?

7 个解决方案

#1


52  

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

正如在gcc中所发生的那样,typeid().name()的结果是被损坏的类名,以获得混乱的版本使用

#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.

其他编译器可能使用不同的命名方案。

#2


13  

use typeid(class).name

使用类型id(类). name

// illustratory code assuming all includes/namespaces etc

// illustratory代码,假设所有包含/名称空间等

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

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

It is important to remember that this gives an implementation defined names.

重要的是要记住,这提供了一个实现定义的名称。

As far as I know, there is no way to get the name of the object at run time reliably e.g. 'A' in your code.

据我所知,在运行时无法可靠地获取对象的名称。代码中的“A”。

EDIT 2:

编辑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)];
}

#3


8  

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

你想要[classname]是" 1 "还是[objectname]是" 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.

如果是这样,这是不可能的。这些名称只是程序员的抽象,实际上并不在生成的二进制代码中使用。您可以为该类提供一个静态变量classname,您将其设置为“1”,并将其设置为一个普通变量objectname,您可以通过方法或构造函数直接对其进行赋值。然后,您可以为类和对象名查询这些方法。

#4


6  

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

要获得类名而不破坏东西,你可以在构造函数中使用func宏:

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

#5


4  

You could try using "typeid".

您可以尝试使用“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.

不过,值得记住的是,typeid的输出是特定于编译器的,因此,即使它在当前平台上生成您想要的内容,它也可能不会在另一个平台上生成。这对你来说可能是个问题,也可能不是。

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.

Edit2:进一步说明之后,您需要将这个“DefineClassName”宏放入您创建的每个类中,并定义一个将调用静态模板函数的“classname”函数。

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:

Edit3:想想……早上第一件事显然是不好的,因为您还不如定义一个成员函数“classname()”,如下所示:

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 ...

在你定义的类中…

#6


2  

Just write simple template:

只写简单的模板:

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

struct A {} a;

void main() {
   std::cout << getClassName(a);
}

#7


2  

An improvement for @Chubsdad answer,

@Chubsdad回答的改进,

//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*

#1


52  

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

正如在gcc中所发生的那样,typeid().name()的结果是被损坏的类名,以获得混乱的版本使用

#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.

其他编译器可能使用不同的命名方案。

#2


13  

use typeid(class).name

使用类型id(类). name

// illustratory code assuming all includes/namespaces etc

// illustratory代码,假设所有包含/名称空间等

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

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

It is important to remember that this gives an implementation defined names.

重要的是要记住,这提供了一个实现定义的名称。

As far as I know, there is no way to get the name of the object at run time reliably e.g. 'A' in your code.

据我所知,在运行时无法可靠地获取对象的名称。代码中的“A”。

EDIT 2:

编辑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)];
}

#3


8  

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

你想要[classname]是" 1 "还是[objectname]是" 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.

如果是这样,这是不可能的。这些名称只是程序员的抽象,实际上并不在生成的二进制代码中使用。您可以为该类提供一个静态变量classname,您将其设置为“1”,并将其设置为一个普通变量objectname,您可以通过方法或构造函数直接对其进行赋值。然后,您可以为类和对象名查询这些方法。

#4


6  

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

要获得类名而不破坏东西,你可以在构造函数中使用func宏:

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

#5


4  

You could try using "typeid".

您可以尝试使用“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.

不过,值得记住的是,typeid的输出是特定于编译器的,因此,即使它在当前平台上生成您想要的内容,它也可能不会在另一个平台上生成。这对你来说可能是个问题,也可能不是。

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.

Edit2:进一步说明之后,您需要将这个“DefineClassName”宏放入您创建的每个类中,并定义一个将调用静态模板函数的“classname”函数。

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:

Edit3:想想……早上第一件事显然是不好的,因为您还不如定义一个成员函数“classname()”,如下所示:

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 ...

在你定义的类中…

#6


2  

Just write simple template:

只写简单的模板:

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

struct A {} a;

void main() {
   std::cout << getClassName(a);
}

#7


2  

An improvement for @Chubsdad answer,

@Chubsdad回答的改进,

//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*