C++中如何获取类名字符串?(利用typeid(obj).name()方法)

typeid(obj).name() 返回的是编译器 ABI 编码的 mangled 名称(如 St6vectorIiSaIiEE),不可读且跨平台不一致;必须用 abi::__cxa_demangle(GCC/Clang)或 __unDName(MSVC)解码才能获得可读类名。

typeid(obj).name() 返回的不是可读类名,而是编译器生成的 mangled 名称,直接用会出问题。

为什么 typeid(obj).name() 不能直接当类名用

它返回的是 ABI 编码后的符号名,比如 St6vectorIiSaIiEE(GCC 下 std::vector 的 mangled 名),不同编译器结果不一致,且标准不保证可读性。C++ 标准只规定 name() 返回“implementation-defined null-terminated byte string”,没说要可读。

如何安全地获取可读类名字符串

必须配合 abi::__cxa_demangle(GCC/Clang)或 UnDecorateSymbolName(MSVC)做 demangling。Linux/macOS 下推荐用:

#include 
#include 
#include 
#include 

std::string get_class_name(const std::type_info& ti) { int status = 0; std::unique_ptr)(void)> name{ abi::__cxa_demangle(ti.name(), nullptr, nullptr, &status), [](void* p) { std::free(p); } }; return (status == 0) ? name.get() : ti.name(); }

// 使用示例 struct Foo {}; Foo f; std::cout << get_class_name(typeid(f)) << "\n"; // 输出 "Foo"

  • status != 0 表示 demangling 失败,退回到原始 name()(不可读但不会崩溃)
  • 必须链接 -lstdc++(GCC)或 -lc++(Clang)
  • MSVC 用户需改用 __unDName,且 typeid(T).name() 本身已部分 demangled,行为不同

替代方案:C++11 起可用模板 + __PRETTY_FUNCTION__

更便携、无需链接额外库,适合调试和日志:

template 
std::string type_name() {
    const char* p = __PRETTY_FUNCTION__;
    const char* q = strrchr(p, ' ');
    if (!q) return "";
    q++;
    const char* r = strchr(q, '[');
    return std::string(q, r ? r - q : strlen(q));
}

// GCC/Clang 下 type_name() → "Foo" // 注意:MSVC 不支持 __PRETTY_FUNCTION,需用 FUNCSIG__

  • 依赖编译器扩展,不是标准 C++,但 GCC/Clang 稳定支持
  • 不适用于运行时对象(只能在编译期推导类型),即不能写 type_name() 后再传参
  • 若类在匿名命名空间里,可能带额外修饰,需额外截取

真正可靠的运行时类名获取,绕不开 demangling;而编译期已知类型的场景,__PRETTY_FUNCTION__ 更轻量。别信 “typeid(x).name() 就是类名” 这种说法——它只是个符号标识符,不是名字。