如何在C++中获取类名作为std::string?求编译时自动实现方案
自动生成类名获取方法的几种方案
当然有更高效的办法!手动给每个类复制粘贴get_name函数不仅繁琐,还很容易因为拼写错误搞出问题,下面几种编译时方案能帮你自动搞定这个需求:
1. 预处理器宏(最直接可靠)
利用C预处理器的字符串化特性,定义一个宏就能自动为类生成get_name虚函数:
#include <string> // 定义宏,自动生成返回类名字符串的虚函数 #define DECLARE_CLASS_NAME(class_name) \ virtual std::string get_name() const override { \ return #class_name; \ } // 用法示例 class Class1 { public: DECLARE_CLASS_NAME(Class1); }; class Class2 { public: DECLARE_CLASS_NAME(Class2); };
这里的#class_name是预处理器的字符串化操作,会把你传入的类名直接转换成对应的字符串字面量,完全避免了手动输入类名的错误。而且这个过程是在编译前完成的,没有任何运行时开销。
2. RTTI(运行时类型信息)
如果可以接受编译器相关的类名格式,也可以用C++的RTTI特性:
#include <string> #include <typeinfo> // 如果需要解析gcc的名字修饰,还要加这个头 // #include <cxxabi.h> class Base { public: virtual ~Base() = default; // 必须包含虚函数才能让typeid动态解析 std::string get_name() const { // 直接返回typeid的结果,注意不同编译器格式不同 const char* raw_name = typeid(*this).name(); // 如果是gcc/clang,可以用下面的代码解析修饰后的名字 // int status; // char* demangled = abi::__cxa_demangle(raw_name, nullptr, nullptr, &status); // std::string name(demangled); // free(demangled); // return name; return raw_name; } }; class Derived : public Base {};
这种方式的好处是不用给每个类加宏,但缺点也很明显:typeid返回的类名格式是编译器相关的,比如GCC会返回带命名空间修饰的乱码字符串,需要额外解析;而且如果类没有虚函数,typeid不会做动态解析,只能返回静态类型的名字。
3. CRTP(奇异递归模板模式)
结合模板和CRTP可以实现更优雅的无宏方案,但同样面临RTTI的名字修饰问题:
#include <string> #include <typeinfo> template<typename Derived> class NameableBase { public: std::string get_name() const { return typeid(Derived).name(); // 同样可以加上名字解析逻辑,参考上面的RTTI示例 } }; // 用法 class Class1 : public NameableBase<Class1> { // 类的其他成员 }; class Class2 : public NameableBase<Class2> { // 类的其他成员 };
这种方式把获取类名的逻辑放到了基类里,避免了重复代码,但还是解决不了类名字符串的格式问题,如果需要精确的类名,还是宏的方式最稳妥。
内容的提问来源于stack exchange,提问作者motam79
相关产品推荐
相关产品推荐

