以编程方式检索 C++ 类名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1024648/
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
Retrieving a c++ class name programmatically
提问by Morgan
I was wondering if it is possible in C++ to retrieve the name of a class in string form without having to hardcode it into a variable or a getter. I'm aware that none of that information is actually used at runtime, therefor it is unavailable, but are there any macros that can be made to create this functionality?
我想知道是否可以在 C++ 中以字符串形式检索类的名称,而无需将其硬编码到变量或 getter 中。我知道在运行时实际上没有使用这些信息,因此它不可用,但是是否可以使用任何宏来创建此功能?
Edit: May be helpful to note that I'm actually trying to retrieve the name of a derived class, and I'm using Visual C++ 2008 Express Edition.
编辑:注意我实际上是在尝试检索派生类的名称,并且我使用的是 Visual C++ 2008 Express Edition,这可能会有所帮助。
回答by Konrad Rudolph
You can use typeid
:
您可以使用typeid
:
#include <typeinfo>
std::cout << typeid(obj).name() << "\n";
However, the type name isn't standardided and may differ between different compilers (or even different versions of the same compiler), and it is generally not human readable because it is mangled.
但是,类型名称不是标准化的,并且在不同的编译器(甚至同一编译器的不同版本)之间可能会有所不同,并且它通常不是人类可读的,因为它被破坏了。
On GCC and clang (with libstdc++ and libc++), you can demangle names using the __cxa_demangle
function(on MSVC demangling does not seem necessary):
在 GCC 和 clang(使用 libstdc++ 和 libc++)上,您可以使用该__cxa_demangle
函数对名称进行 demangle (在 MSVC 上 demangling 似乎没有必要):
#include <cxxabi.h>
#include <cstdlib>
#include <memory>
#include <string>
std::string demangle(char const* mangled) {
auto ptr = std::unique_ptr<char, decltype(& std::free)>{
abi::__cxa_demangle(mangled, nullptr, nullptr, nullptr),
std::free
};
return {ptr.get()};
}
This will stillnot necessarily be a readable name — for instance, std::string
is a type name for the actual type, and its complete type name in the current libstdc++ is std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
; by contrast, in the current libc++ it's std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
. “Prettifying” type aliases is unfortunately not trivial.
这仍然不一定是一个可读的名称——例如,std::string
是实际类型的类型名称,它在当前 libstdc++ 中的完整类型名称是std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
; 相比之下,在当前的 libc++ 中,它是std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
. 不幸的是,“美化”类型别名并非易事。
回答by fchen
If you just want to check if it's certain class, then
如果你只是想检查它是否是某个类,那么
typeid(obj) == typeid(CSubClass)
will always work regardless of the implementations.
无论实现如何,都将始终有效。
Otherwise, a convenient way is to declare:
否则,一种方便的方法是声明:
virtual const char* classname() { return "CMyClass";}
and implement per subclass.
并实现每个子类。
回答by jbillfinger
The typeid(obj).name()
thing always gives the type of the variable as it was declared, not the actual type (class) of the object. If the variable obj is assigned to an instance of a subclass of the class that obj was declared as, typeid doesn't reveal that, unfortunately.
该typeid(obj).name()
事情总是给人变量,因为它被宣布,而不是实际的类型(类)对象的类型。不幸的是,如果将变量 obj 分配给 obj 声明为的类的子类的实例,则 typeid 不会显示这一点。
回答by blongho
What about this,
那这个呢,
Tested on Windows 10 using Visual Studio 2019 (v142).
使用 Visual Studio 2019 (v142) 在 Windows 10 上测试。
#include <iostream>
#include <typeinfo>
#include <string>
/**
@author blongho
@fn template<typename Object> std::string classNameOf()
@brief Determine the class name of an object
@tparam Object Type of the object.
@returns A name of the class
@date 2019-09-06
*/
template<typename Object>
std::string classNameOf() {
std::string name = typeid(Object).name(); //* user defined types gives "class Type"*\
size_t spacePosition = name.find_first_of(" ");
if (spacePosition != std::string::npos) {
return name.substr(spacePosition + 1, name.length());
}
return name; // mostly primitive types
}
class Person {
private:
/* data */
public:
Person() {};
~Person() {};
};
class Data
{
private:
/* data */
public:
Data() {};
~Data() {};
};
struct Type {};
int main() {
std::cout << "Class name of Person() is \"" << classNameOf<Person>() << "\"\n";
std::cout << "Class name of Data() is \"" << classNameOf<Data>() << "\"\n";
std::cout << "Class name of Type() is \"" << classNameOf<Type>() << "\"\n";
std::cout << "Class name of double is \"" << classNameOf<double>() << "\"\n";
std::cout << "Class name of std::string is \"" << classNameOf<std::string>() << "\"\n";
std::cout << "Class name of int is \"" << classNameOf<int>() << "\"\n";
std::cout << "Class name of float is \"" << classNameOf<float>() << "\"\n";
std::cout << "Class name of char is \"" << classNameOf<char>() << "\"\n";
return 0;
}
Output
Output
Class name of Person() is "Person"
Class name of Data() is "Data"
Class name of Type() is "Type"
Class name of double is "double"
Class name of std::string is "std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >"
Class name of int is "int"
Class name of float is "float"
Class name of char is "char"
In Ubuntu 18.04,
在 Ubuntu 18.04 中,
g++ -o test src/main.cpp
./test
Class name of Person() is "6Person"
Class name of Data() is "4Data"
Class name of Type() is "4Type"
Class name of double is "d"
Class name of std::string is "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"
Class name of int is "i"
Class name of float is "f"
Class name of char is "c"