2 动态反射
C++中经常会出现静态和动态相关的术语,比如静态类型、动态类型、静态绑定、动态绑定等,无一例外动态是指运行时,静态是指编译时。在反射的场景下依然如此。那么对应的动态反射就是在运行时获取函数的元数据,包含成员,函数等等,那么为了获取对应的属性,我们需要利用相关结构保存详细的属性信息。假如我们要实现一个简单的动态反射demo,我们能够考虑到类的属性有:
成员变量(FiledInfo):
名称;
类型;
相对偏移;
函数描述(MethodInfo):
名称;
返回值类型;
参数列表;
类型(TypeInfo):
名称;
成员列表;
函数列表。
基于以上的推断,我们能够很快写出三个相关的简单类:
class FieldInfo {
public:
FieldInfo()
: _name(""), _type(typeid(void)) {}
FieldInfo(const std::string& name, std::type_index type)
: _name(name), _type(type) {}
std::string getName() const { return _name; }
std::type_index getType() const { return _type; }
private:
std::string _name; // 字段名称
std::type_index _type; // 字段类型
};
class MethodInfo {
public:
MethodInfo()
: _name(""), _returnType(typeid(void)), _paramTypes() {}
MethodInfo(const std::string& name, std::type_index returnType, const std::vector
: _name(name), _returnType(returnType), _paramTypes(paramTypes) {}
std::string getName() const { return _name; }
std::type_index getReturnType() const { return _returnType; }
const std::vector
private:
std::string _name; // 方法名称
std::type_index _returnType; // 返回类型
std::vector
};
// 类型信息
class TypeInfo {
public:
TypeInfo()
: _name(""), _creator(nullptr) {} // 默认构造函数
TypeInfo(const std::string& name)
: _name(name), _creator(nullptr) {}
void addField(const FieldInfo& field) {
_fields[field.getName()] = field;
}
void addMethod(const MethodInfo& method) {
_methods[method.getName()] = method;
}
void setCreator(std::function
_creator = creator;
}
void* createInstance(std::vector
return _creator ? _creator(args) : nullptr;
}
std::string getName() const { return _name; }
bool hasField(const std::string& fieldName) const {
return _fields.find(fieldName) != _fields.end();
}
bool hasMethod(const std::string& methodName) const {
return _methods.find(methodName) != _methods.end();
}
private:
std::string _name;
std::unordered_map
std::unordered_map
std::function
};
需要注意的是这里展示的属性的基本描述是不全的,很多时候类型还需要考虑继承,属性控制等,而且MethodInfo没有实现函数调用的接口(实际实现起来比较简单)。具体需要什么属性和方法要根据你具体的工程而来。
有了这些存储类型的基本信息,我们只需要还需要一个全局的注册器注册对应的类型来进行统一管理。
class TypeRegistry {
public:
static TypeRegistry& instance() {
static TypeRegistry registry;
return registry;
}
void registerType(const std::string& name, const TypeInfo& typeInfo) {
_types[name] = typeInfo;
}
void registerTypeWithCreator(const std::string& name, const TypeInfo& typeInfo, std::function
_types[name] = typeInfo;
_types[name].setCreator(creator);
}
const TypeInfo* getType(const std::string& name) const {
auto it = _types.find(name);
return (it != _types.end()) ? &it->second : nullptr;
}
private:
std::unordered_map
};
有了这些信息,我们就能够在运行时根据类型名称获取到对应的类型信息,从而进行相关的操作。比如下面的ExampleClass创建时会自动注册当前类的类型信息,当然如果嫌弃使用registerType不方便,也可以通过宏来实现,避免重复代码。
class ExampleClass {
public:
ExampleClass(int value) : _value(value) {
registerType();
}
void setValue(int value) {
_value = value;
}
int getValue() const {
return _value;
}
static void* createInstance(std::vector
if (args.empty()) return nullptr; // 参数检查
int value = *static_cast
return new ExampleClass(value); // 创建实例
}
private:
void registerType() {
TypeInfo typeInfo("ExampleClass");
typeInfo.addField(FieldInfo("value", typeid(int)));
typeInfo.addMethod(MethodInfo("setValue", typeid(void), { typeid(int) }));
typeInfo.addMethod(MethodInfo("getValue", typeid(int), {}));
// 注册带参数的创建函数
typeInfo.setCreator(createInstance);
TypeRegistry::instance().registerType("ExampleClass", typeInfo);
}
int _value;
};
对应的测试代码如下:
TEST(TypeRegistryTest, TypeRegistration) {
ExampleClass example(42);
const TypeInfo* typeInfo = TypeRegistry::instance().getType("ExampleClass");
ASSERT_NE(typeInfo, nullptr);
EXPECT_EQ(typeInfo->getName(), "ExampleClass");
EXPECT_TRUE(typeInfo->hasField("value"));
EXPECT_TRUE(typeInfo->hasMethod("setValue"));
EXPECT_TRUE(typeInfo->hasMethod("getValue"));
// 测试对象创建
int value = 42;
std::vector
void* instance = typeInfo->createInstance(args);
ExampleClass* createdInstance = static_cast
EXPECT_EQ(createdInstance->getValue(), 42);
delete createdInstance; // 清理动态分配的内存
}
TEST(FieldInfoTest, FieldInfoCreation) {
FieldInfo field("value", typeid(int));
EXPECT_EQ(field.getName(), "value");
EXPECT_EQ(field.getType(), typeid(int));
}
TEST(MethodInfoTest, MethodInfoCreation) {
std::vector
MethodInfo method("setValue", typeid(void), paramTypes);
EXPECT_EQ(method.getName(), "setValue");
EXPECT_EQ(method.getReturnType(), typeid(void));
EXPECT_EQ(method.getParamTypes().size(), 1);
EXPECT_EQ(method.getParamTypes()[0], typeid(int));
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}