如何从 C++ 对象中获取类名?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3649278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:22:32  来源:igfitidea点击:

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

c++class

提问by Lazer

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++ 是否提供任何机制来实现这一点?

回答by Scott Wales

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 versionuse

正如在 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.

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

回答by Chubsdad

use typeid(class).name

typeid(class).name

// illustratory code assuming all includes/namespaces etc

// 假设所有包含/命名空间等的说明性代码

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

回答by grungegurunge

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

要在不修改内容的情况下获取类名,您可以在构造函数中使用func宏:

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

回答by Alexander Rafferty

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

你想让 [classname] 是 'one' 而 [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.

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

回答by Goz

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.

这不适用于“对象”名称,但您知道对象名称,因此您只需要将其存储在某处。Compiler 不关心您命名对象的名称。

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”宏放在您创建的每个类中,并定义一个调用静态模板函数的“类名”函数。

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

在你定义它的时候进入类......

回答by sea-kg

Just write simple template:

只需编写简单的模板:

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

struct A {} a;

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

回答by OhadM

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*

回答by voltento

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>();
}