网站系统的运营和维护wordpress热门分类

当前位置: 首页 > news >正文

网站系统的运营和维护,wordpress热门分类,局域网建网站的详细步骤,自媒体网络公司经营范围0. 简介 最近看很多端到端的工作#xff0c;发现大多数都是基于mmdet3d来做的#xff0c;而这个里面用的比较多的形式就是反射机制#xff0c;这样其实可以比较好的通过类似plugin的形式完成模型模块的插入。当然我们这里不是来分析python的反射机制的。我们这篇文章主要来…0. 简介 最近看很多端到端的工作发现大多数都是基于mmdet3d来做的而这个里面用的比较多的形式就是反射机制这样其实可以比较好的通过类似plugin的形式完成模型模块的插入。当然我们这里不是来分析python的反射机制的。我们这篇文章主要来介绍C上实现反射。

  1. 反射的用途 一般来说就是序列化反序列化啦。比如说你想通过网络传递一个实例或者把它保存到文件里以后再取出来放到程序里这就需要反射 反射其实还能细分为静态反射和动态反射 静态反射就是在编译期生成反射信息动态反射就是在运行时生成反射信息动态反射显然需要一套强大的运行时和动态类型系统也是显然的很复杂 在来还有侵入式非侵入式之分。非侵入式的反射允许不对源码进行修改就能实现反射侵入式呢就得对源码动动手脚了。 第一种实现思路是在源码里加入大量的反射信息手动注册反射。 这种库的代表是rttr 第二种实现思路是通过parser解析源码自动生成反射信息。 这种库的代表是QTUE的反射系统 第三种 用大量的编译期模板生成元信息然后构建一套巨抽象的运行时比如Ubpa/UDRefl 第四种 利用调试器的运行时信息来生成反射代码这种想法并非无稽之谈思考下lldbgdb明显能在运行时获取字段内容类型 第五种 绑架编译器 clang提供了插件功能。事实上也有大佬做了这些都有比较详细的例子。
  2. 源码添加手动注册 这种用的是比较多的一般的是自定义一个反射类然后用模板来实现一个模板类管理类名和类构造函数的映射关系并提供构造对象的接口每个基类需要初始化一个这样的管理对象。 下面我们提供一个对应的 static 模板函数用来保存和返回对应的管理对象。并使用模板函数和 new 操作符作为每个类的构造函数。 实现一个简单的 helper 模板类提供作为注册的简单封装并封装宏实现注册。下面是具体代码 #ifndef BASE_H #define BASE_H #include string #include map #include iostream// 使用模板每个基类单独生成一个 ClassRegister // 好处是需要反射的类不需要去继承 Object 对象 // ClassRegister 用来管理类名-类构造函数的映射对外提供根据类名构造对象对函数 templatetypename ClassName class ClassRegister {public:typedef ClassName* (Constructor)(void);private:typedef std::mapstd::string, Constructor ClassMap;ClassMap constructormap;public:// 添加新类的构造函数void AddConstructor(const std::string class_name, Constructor constructor) {typename ClassMap::iterator it constructormap.find(class_name);if (it ! constructormap.end()) {std::cout error!;return;}constructormap[class_name] constructor;}// 根据类名构造对象ClassName CreateObject(const std::string class_name) const {typename ClassMap::const_iterator it constructormap.find(class_name);if (it constructormap.end()) {return nullptr;}return ((it-second))();} };// 用来保存每个基类的 ClassRegister static 对象用于全局调用 template typename ClassName ClassRegisterClassName GetRegister() {static ClassRegisterClassName class_register;return class_register; }// 每个类的构造函数返回对应的base指针 template typename BaseClassName, typename SubClassName BaseClassName NewObject() {return new SubClassName(); }// 为每个类反射提供一个 helper构造时就完成反射函数对注册 templatetypename BaseClassName class ClassRegisterHelper {public:ClassRegisterHelper(const std::string sub_class_name,typename ClassRegisterBaseClassName::Constructor constructor) {GetRegisterBaseClassName().AddConstructor(sub_class_name, constructor);}~ClassRegisterHelper(){} };// 提供反射类的注册宏使用时仅提供基类类名和派生类类名 #define RegisterClass(base_class_name, sub_class_name) \static ClassRegisterHelperbase_class_name \sub_class_name##_register_helper( #sub_class_name, NewObjectbase_class_name, sub_class_name);// 创建对象的宏 #define CreateObject(base_class_name, sub_class_name_as_string) \GetRegisterbase_class_name().CreateObject(sub_class_name_as_string)#endif下面是使用的示例 #include iostream #include memory #include cstring #include base3.h using namespace std;class base {public:base() {}virtual void test() { std::cout Im base! std::endl; }virtual ~base() {} };class A : public base {public:A() { cout A constructor! endl; }virtual void test() { std::cout Im A! std::endl; }~A() { cout A destructor! endl; } };// 注册反射类 A RegisterClass(base, A);class B : public base {public :B() { cout B constructor! endl; }virtual void test() { std::cout Im B!; }~B() { cout B destructor! endl; } };// 注册反射类 B RegisterClass(base, B);class base2 {public:base2() {}virtual void test() { std::cout Im base2! std::endl; }virtual ~base2() {} };class C : public base2 {public :C() { cout C constructor! endl; }virtual void test() { std::cout Im C! std::endl; }~C(){ cout C destructor! endl; } };// 注册反射类 C RegisterClass(base2, C);int main() {// 创建的时候提供基类和反射类的字符串类名base* p1 CreateObject(base, A);p1-test();delete p1;p1 CreateObject(base, B);p1-test();delete p1;base2* p2 CreateObject(base2, C);p2-test();delete p2;return 0; }3. parser解析源码自动生成反射信息 要实现自动生成反射信息的功能我们需要编写一个代码解析器用于解析源代码并提取出需要的信息。一般来说代码解析器会将源码转换为一棵抽象语法树AST然后对这棵树进行遍历提取出需要的信息。 要使用Clang来解析源码并自动生成反射信息可以借助Clang的ASTAbstract Syntax Tree来实现。以下是一个简单的示例代码演示如何使用Clang来解析源码并生成反射信息 #include iostream #include string #include clang/Tooling/Tooling.h #include clang/Tooling/CommonOptionsParser.h #include clang/Frontend/FrontendActions.h #include clang/Tooling/Tooling.h #include clang/AST/ASTConsumer.h #include clang/AST/ASTContext.h #include clang/ASTMatchers/ASTMatchers.h #include clang/ASTMatchers/ASTMatchFinder.husing namespace clang; using namespace clang::tooling; using namespace clang::ast_matchers;class ReflectionGenerator : public MatchFinder::MatchCallback { public:virtual void run(const MatchFinder::MatchResult Result) {if (const CXXRecordDecl *Record Result.Nodes.getNodeAsCXXRecordDecl(class)) {std::string className Record-getNameAsString();std::cout Registering class: className std::endl;// 在这里可以生成反射信息并注册类// 获取类名并输出到控制台std::cout Class name: className std::endl;// 遍历类的字段并输出到控制台for (const FieldDecl *Field : Record-fields()) {std::string fieldName Field-getNameAsString();std::cout Field name: fieldName std::endl;}}} };int main(int argc, const char **argv) {CommonOptionsParser OptionsParser(argc, argv);ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());ReflectionGenerator Generator;MatchFinder Finder;Finder.addMatcher(cxxRecordDecl().bind(class), Generator);return Tool.run(newFrontendActionFactory(Finder).get()); }在这个示例代码中我们通过Clang的AST来解析源码并使用AST Matchers来匹配C类的声明。当匹配到一个类声明时ReflectionGenerator类的run方法会被调用我们可以在这里生成反射信息并注册类。下面我们对上面代码中主要部分进行详细解释 ReflectionGenerator类这是一个继承自MatchFinder::MatchCallback的自定义类用于处理匹配到的AST节点。在run方法中根据匹配到的C类定义获取类名并输出到控制台同时遍历类的字段并输出字段名。 main函数 创建CommonOptionsParser对象和ClangTool对象用于解析命令行参数和运行Clang工具。创建ReflectionGenerator对象和MatchFinder对象用于注册匹配规则和处理匹配结果。通过Tool.run方法运行Clang工具并传入匹配规则和处理结果的工厂对象。 cxxRecordDecl matcher使用Finder.addMatcher添加了一个匹配规则用于匹配C类的定义。当匹配到符合规则的AST节点时会调用ReflectionGenerator的run方法进行处理。 反射信息生成在ReflectionGenerator的run方法中获取到类名和字段名后输出到控制台。这里展示了获取类名和字段名的基本操作您可以根据需求进一步扩展生成反射信息的逻辑。
    此外这里我们可以通过attribute((annotate(…))) 来完成相同的操作。attribute((annotate(…))) 的意义是为代码中的类、字段、函数等元素添加自定义的元数据信息。这些信息可以用于实现反射、元编程、代码生成等功能。通过注解我们可以为代码中的各种元素添加描述、标签、类型信息等使其更具有可读性和可维护性同时也可以在程序运行时动态地获取这些信息并进行相应的操作。在下面的示例中我们使用了 attribute((annotate(reflect_class, BarClass)))、attribute((annotate(reflect_property, int foo)))、attribute((annotate(reflect_func, void setFoo(int))) 等注解来为类、字段和函数添加反射信息。这些注解可以帮助我们在编译时或运行时识别和操作这些元素实现更高级的功能。 以下是一个完整的示例代码其中使用了属性拓展和注解来实现反射功能 #include iostream#define RFL_CLASS(…) attribute((annotate(reflect_class, #VA_ARGS))) #define RFL_PROPERTY(…) attribute((annotate(reflect_property, #VA_ARGS))) #define RFL_FUNC(…) attribute((annotate(reflect_func, #VA_ARGS)))class RFL_CLASS(BarClass) Bar { public:RFL_PROPERTY(int foo) int foo;RFL_FUNC(void setFoo(int)) void setFoo(int value) {foo value;}RFL_FUNC(int getFoo()) int getFoo() {return foo;} };int main() {Bar bar;bar.setFoo(42);std::cout Value of foo: bar.getFoo() std::endl;return 0; }在 RFL_CLASS 宏和类定义中我们添加了一个字符串参数用于指定类的名称。这样可以在反射时更准确地标识类。在 RFL_PROPERTY 宏和字段定义中我们添加了一个字符串参数用于指定字段的类型和名称。这样可以在反射时更准确地标识字段。在 RFL_FUNC 宏和成员函数定义中我们添加了一个字符串参数用于指定函数的签名。这样可以在反射时更准确地标识函数。 在main函数中我们创建了一个Bar对象并使用setFoo和getFoo函数来设置和获取foo字段的值。这些函数的签名和类/字段的信息都被注解添加到了代码中以便在反射时能够准确地识别和访问它们。
  3. 元信息结构反射机制 要在C中构建一套可以在运行时使用的反射机制你可以利用模板元编程在编译期生成类型元信息并在运行时通过这些元信息进行反射操作。 首先我们需要定义一种数据结构来存储类型的元信息。 #include iostream #include string #include typeinfo #include typeindex #include unordered_map #include vectorstruct FieldInfo {std::string name;std::type_index type;size_t offset; };struct TypeInfo {std::string name;std::vectorFieldInfo fields; };然后我们需要一个机制来自动生成这些元信息。这里我们用模板和宏来实现这一点。 #define REFLECTABLE(…) \friend struct Reflection; \static void reflect(Reflection r) { \r.registerType(typeid(*this), #VA_ARGS, VA_ARGS); }class Reflection { public:templatetypename Tvoid registerType(std::type_index type, const std::string fieldNames, T instance) {std::istringstream stream(fieldNames);std::string fieldName;size_t offset 0;while (std::getline(stream, fieldName, ,)) {trim(fieldName);TypeInfo typeInfo typeRegistry[type];typeInfo.name type.name();typeInfo.fields.push_back({ fieldName, typeid(instance. * (T::*)(T:: *) fieldName), offset });offset sizeof(fieldName);}}templatetypename Tconst TypeInfo getTypeInfo() {return typeRegistry[std::type_index(typeid(T))];}private:std::unordered_mapstd::type_index, TypeInfo typeRegistry;void trim(std::string s) {s.erase(0, s.find_first_not_of( ));s.erase(s.find_last_not_of( ) 1);} };现在我们可以定义一个类并使用宏来使其成为可反射的。 class MyClass { public:int x;float y;std::string z;REFLECTABLE(x, y, z) };4. 使用反射机制 最后我们可以在运行时使用反射机制来访问类的元信息。 int main() {MyClass obj;Reflection reflection;// 注册类型信息obj.reflect(reflection);// 获取类型信息const TypeInfo typeInfo reflection.getTypeInfoMyClass();// 输出字段信息std::cout Type: typeInfo.name std::endl;for (const auto field : typeInfo.fields) {std::cout Field: field.name , Type: field.type.name() , Offset: field.offset std::endl;}return 0; }FieldInfo 和 TypeInfo 结构体这些结构体用于存储字段和类型的元信息。Reflection 类这个类负责注册和存储类型元信息并提供查询接口。REFLECTABLE 宏这个宏用于简化类型元信息的注册过程。它声明一个友元函数这个函数可以访问类的私有成员并在编译期生成字段的名字和类型信息。registerType 和 getTypeInfo 方法 registerType 方法在编译期处理传入的字段名称生成对应的字段信息并存储在一个哈希表中。getTypeInfo 方法在运行时查询并返回存储的类型信息。 MyClass 类这是一个简单的示例类通过 REFLECTABLE 宏声明它是可反射的。main 函数在 main 函数中我们创建一个 MyClass 的实例并注册它的类型信息然后查询并输出这些信息。 这个例子展示了如何在 C 中利用模板和宏实现一个简单的反射机制。这个机制允许你在运行时访问类型的元信息从而实现各种动态操作例如序列化和反序列化、类型检查和动态调用等等。
  4. 调试器的运行时信息形成反射 使用调试器的运行时信息来生成反射代码是一种非常高级的技术通常需要结合调试器提供的 API 和脚本语言例如 Python进行自动化处理。这个过程大致可以分为以下几个步骤 使用调试器获取目标程序的运行时信息。解析并提取元信息。生成对应的反射代码。 首先编写一个简单的 C 程序 // example.cpp #include iostream #include vector #include stringclass MyClass { public:int x;float y;std::string z;void print() {std::cout x: x , y: y , z: z std::endl;} };int main() {MyClass obj;obj.x 10;obj.y 20.5f;obj.z Hello, World!;obj.print();return 0; }编译这个程序 g -g example.cpp -o example…详情请参照古月居