c++ 反射类型
来自:
实现代码===
//
// Created by lizhen on 2017/9/29.
// #ifndef BOOST_ALL_CALLBACKFUNCTION_H
#define BOOST_ALL_CALLBACKFUNCTION_H #include <iostream>
#include <map>
#include <string>
using namespace std; typedef void* (*PTRCreateObject)(void);//定义一个函数指针类型,用于指向创建类实例的回调函数 class ClassFactory{
private:
map<string,PTRCreateObject >map_classMap;
ClassFactory(){};
public:
void *getClassByName(string className);
void registClass(string name,PTRCreateObject method);
static ClassFactory& getInstance();
}; ClassFactory& ClassFactory::getInstance() {
static ClassFactory sLo_factory;
return sLo_factory;
} void* ClassFactory::getClassByName(string className) {
map<string,PTRCreateObject >::const_iterator iter;
iter = map_classMap.find(className);
if(iter==map_classMap.end()){
return NULL;
}else{
return iter->second();
}
} void ClassFactory::registClass(string name, PTRCreateObject method) {
map_classMap.insert(pair<string,PTRCreateObject>(name,method));
} class RegisterAction{
public:
RegisterAction(string className,PTRCreateObject ptrCreateFn){
ClassFactory::getInstance().registClass(className,ptrCreateFn);
}
}; //================================ClassA
class TestClassA{
public:
void m_print(){
cout<<"hello TestClassA"<<endl;
}
};
TestClassA* createObjTestClassA(){
return new TestClassA();
}
RegisterAction g_create_RegisterTestClassA("TestClassA",(PTRCreateObject)createObjTestClassA());
//<----- //================================ClassB
//test class B
class TestClassB{
public:
void m_print(){
cout<<"hello TestClassB"<<endl;
}
};
TestClassB* createObjTestClassB(){
return new TestClassB();
}
RegisterAction g_create_RegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB());
//<--- #define REGISTER(className) \
className* objectCreater##className(){ \
return new className(); \
} \
RegisterAction g_createrRegister##className( \
#className,(PTRCreateObject)objectCreater##className) class classC{
public:
void m_print(){
std::cout<<"hello classC"<<std::endl;
}
}; REGISTER(classC);
class Reflact{
public:
void run(){
TestClassA* ptrObjA = (TestClassA*)ClassFactory::getInstance().getClassByName("TestClass");
ptrObjA->m_print();
//REGISTER(classC); classC* ptr_c = (classC*)ClassFactory::getInstance().getClassByName("classC");
ptr_c->m_print();
}
}; #endif //BOOST_ALL_CALLBACKFUNCTION_H
=====
转自http://blog.csdn.net/brighlee/article/details/72885219
前言
反射的概念:
指程序在运行时,访问、检测和修改它本身状态或行为的一种能力。wikipedia
简单的来说,就是一种自描述和自控制的能力。如果联想到镜子,就可以很好的理解,你能通过镜子看到自己,包括自己的动作,自己的外表。唯一不同的地方是,计算机语言的反射能力还包含对看到的自己采取措施。
反射的作用
在计算机编程语言中,反射机制可以用来:
- 获取类型的信息,包括属性、方法
- 动态调用方法
- 动态构造对象
- 从程序集中获得类型
反射的缺点
- 性能:反射可以理解成是一种解释操作,这个过程总是要慢于直接调用的。当然,性能问题的程度是可以控制的,如果程序在很少涉及的地方使用,性能将不会是一个问题。
- 反射模糊了程序内部实际发生的事情,会比直接代码更加复杂。
缺点不能掩饰其优点,针对不同的场景使用合理的技术才是最高境界。
反射的使用场景
- 序列化(Serialization)和数据绑定(Data Binding)
- 远程方法调用(RMI)
- 对象/关系数据映射(O/R mapping)
关于c++的反射
我们知道,Java是原生支持反射机制的,通过Class类可以通过名称获得类对象,进一步操作。Python也支持反射机制,可以通过globals()获取对象map,也可以通过inspect模块,提供了自省的方法。但是C++呢?C++原生不支持反射机制,RTTI(运行时类型识别)也仅仅提供了类型的判断。
开闭原则是设计模式的原则之一,对修改是封闭,对扩展开放。一般来说,需要我们对类进行抽象,针对抽象的类进行编程。许多的设计模式中,为了能够满足这一点,我们常常使用一个配置文件,映射字符串与类型。然后通过反射机制获得字符串对应的对象,然后自动装配已达到易于扩展的目的。
本文主要介绍两个小的场景如何实现C++反射。实际上,C++并不是对反射支持的很好,要支持动态和静态反射,还需要慢慢去寻找,我给出一些资料
本文讨论如何在C++中实现简单的反射。
场景
C++序列化,与反序列化。序列化就是将对象编程二进制的形式存储在磁盘上,或者通过网络传输给另一台机器。反序列化就是序列化的逆过程。但是这个逆过程,必须要根据字符串来判断将二进制流转化成什么类型的对象。
工厂模式,常常是根据一个字符串来获取想要的对象。但是为了满足开闭原则,我们不能简单的在工厂类中不断的修改生产函数来扩展不同的类型。这个时候,需要利用反射,使用抽象类。
实现
思路是:
- 使用map,映射字符串和生产函数
- 每次构造新类型时,将生产函数注册到map中
- 工厂函数通过map获得生产函数,建造不同的对象
方案一
- map存储在Object抽象父类中
- 使用ClassInfo辅助类型保存子类对象(包括了子类对象的构造函数)
- map映射结构—->子类名称:ClassInfo*
// Reflex.h
class Object{
public:
Object(){}
virtual ~Object(){}
static bool Register(ClassInfo *ci); // 注册函数
static Object *CreateObject(string name);
} using ObjectConstructorFn = Object *(*)(void); // 构造函数指针
class ClassInfo {
public:
ClassInfo(const string classname, ObjectConstructorFn ctor)
:class_name_(classname), m_object_constructor_(ctor) {
Object::Register(this); // 注入到Object中
} virtual ~ClassInfo(){};
Object *CreateObject() const { // 返回当前类型的构造函数
return m_object_constructor_ ? (*m_object_constructor_) : ;
} const string GetClassName() const {return class_name_;}
ObjectConstructorFn GetConstructor() {return m_object_constructor_;} private:
string class_name_;
ObjectConstructorFn m_object_constructor_; // 维护对象信息
} ==============================================================
// Reflex.cpp
#include "Reflex.h" static unordered_map<string, ClassInfo *> *class_map = nullptr; // 延迟到第一次注册 bool Object::Register(ClassInfo *ci) {
if (!class_map) {
class_map = new unordered_map<string, ClassInfo *>();
} if (ci) {
// 如果没有注册过
string c_name = ci -> GetClassName();
if (class_map -> find(c_name) == class_map -> end()) {
class_map[c_name] = ci;
}
return true;
} return false;
} Object *Object::CreateObject(string name) {
// 如果注册过就直接调用classinfo的createobject
if (class_map -> find(name) != class_map.end())
return class_map[name] -> CreateObject(); return nullptr;
} ==============================================================
// test.cpp
class A : public Object {
public:
A(){}
~A(){}
ClassInfo *GetClassInfo const{ return &m_class_info_;} // 自定义生产函数
static Object *CreateObject() {
return new A;
} protected:
static ClassInfo m_class_info_;
} // 最重要的一步,将当前类注册到Object中
ClassInfo A::m_class_info_("A", A::CreateObject); int main() {
Object *obj = Object::CreateObject("A");
delete obj; return ;
}
上面的代码实现了简单的反射机制,但是还不够好。每次构建类都需要写许多重复性的代码。而C++的宏为我们提供了很好的工具来简化重复性的代码。如下:
// Reflex.h // 向类中添加 class_info 属性以及 CreateObject、GetClassInfo方法
#define DECLEAR_CLASS(name) \
protected: \
static ClassInfo m_class_info_; \
public:
ClassInfo *GetClassInfo const; \
static Object *CreateObject(); \ // 实现CreateObject和GetClassInfo两个方法
#define IMPLEMENT_CLASS_COMMON(name, func) \
ClassInfo name::m_class_info_((#name), (ObjectConstructorFn) func); \ ClassInfo *name::GetClassInfo() const \
{ return &name::m_class_info_;} // classInfo 属性的初始化
#define IMPLEMENT_CLASS(name) \
IMPLEMENT_CLASS_COMMON(name, name::CreateObject) \
Object* name::CreateObject() \
{ return new name;} ==============================================================
// test.cpp
class B : public Object {
DECLEAR_CLASS(B)
public:
B(){}
~B(){}
}; IMPLEMENT_CLASS(B)
方案二
- map存储在单例工厂类中
- 定义RegisterAction类型完成注册动作
- 同样使用宏将重复性的代码简化
//工厂类的定义
class ClassFactory{
private:
map<string, PTRCreateObject> m_classMap ;
ClassFactory(){}; //构造函数私有化 public:
void* getClassByName(string className);
void registClass(string name, PTRCreateObject method) ;
static ClassFactory& getInstance() ;
}; //工厂类的实现
//@brief:获取工厂类的单个实例对象
ClassFactory& ClassFactory::getInstance(){
static ClassFactory sLo_factory;
return sLo_factory ;
} //@brief:通过类名称字符串获取类的实例
void* ClassFactory::getClassByName(string className){
map<string, PTRCreateObject>::const_iterator iter;
iter = m_classMap.find(className) ;
if ( iter == m_classMap.end() )
return NULL ;
else
return iter->second() ;
} //@brief:将给定的类名称字符串和对应的创建类对象的函数保存到map中
void ClassFactory::registClass(string name, PTRCreateObject method){
m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ;
} //注册动作类
class RegisterAction{
public:
RegisterAction(string className,PTRCreateObject ptrCreateFn){
ClassFactory::getInstance().registClass(className,ptrCreateFn);
}
}; ============================================================== //test class B
class TestClassB{
public:
void m_print(){
cout<<"hello TestClassB"<<endl;
};
}; //@brief:创建类实例的回调函数
TestClassB* createObjTestClassB{
return new TestClassB;
}
//注册动作类的全局实例
RegisterAction g_creatorRegisterTestClassB("TestClassB",(PTRCreateObject)createObjTestClassB); ==============================================================
// 使用宏简化重复性代码 #define REGISTER(className) \
className* objectCreator##className(){ \
return new className; \
} \
RegisterAction g_creatorRegister##className( \
#className,(PTRCreateObject)objectCreator##className)
宏
既然提到了宏,这里简单的复习一下,宏是由 #define 定义而来。在预处理阶段进行宏展开。它的格式是:
#define <宏名> (<参数表>) <宏体>
#define N 2 + 2 // 仅仅是字符串替换
#define N (2 + 2) // 也是字符串 ,但是是(2 + 2) #define area(x) (x) * (x) // 带参的宏定义参会当作字符串直接替换 三种特殊的符号:
# #define Conn(x, y) x##y // 表示连接,数字,字符串都可以
## #define ToString(x) #x // 就是加上双引号
#@ #define ToChar(x) #@x //就是加上单引号, 越界会报错
总结
反射在很多情况下都需要使用,应用场景比较广泛,希望读者能够仔细阅读代码。将反射机制使用在自己的工程里,实现一些设计良好的框架。另外,C++宏的使用可以极大的简化一些重复性的代码,可以仔细研究一下。
=============
来自http://blog.csdn.net/scythe666/article/details/51718864
在 C++ 中实现反射
反射(Reflection)是许多语言(如 C#,Java)都拥有的特性,用于在运行时获取类型信息,大大的提高了编程的灵活性,比如利用反射可以极大的简化 json/xml 解析、脚本绑定、属性编辑器等的实现。但是 C++ 并没有提供反射的支持,本文讨论在 C++ 中实现反射机制的一种方式。
实现原理
在 C# 等语言中,类型信息是在编译时由编译器解析并存储到元数据(Meta Data)中的,其中包括类的名称、方法、属性等信息。每新建立一个类,编译器就会自动生成对应的类型信息,类型信息会被关联在每一个对象上。
但是在 C++ 中,编译器并没有为我们做这样的事情,我们只能自己将这些信息获取并保存下来。我们使用类似下面的结构存储类的相关信息:
// 类信息
class Type {
// 类名
std::string name; // 基类
const Type* baseType; // 是否是枚举类型
bool isEnum; // 构造方法
std::vector<const Constructor*> constructors; // 属性
std::unordered_map<std::string, const Field*> fieldsMap; // 方法,由于要支持重载,所以一个方法名对应多个方法
std::unordered_map<std::string, std::vector<const Method*>> methodsMap;
};
// 引用类型
enum class ReferType {
None, // 无引用类型(值类型)
Refer, // 左值引用
RightRefer, // 右值引用
}; // 修饰类型,比如 int*、const Type、float&
class QualifiedType {
// 基本类型
const Type* type = nullptr; // 是否使用 const 修饰
bool isConst = false; // 是否使用 volatile 修饰
bool isVolatile = false; // 指针层级数量
int pointerCount = ; // 引用类型
ReferType referType = ReferType::None;
}; // 属性
class Field {
// 属性名
std::string name; // 所属的类
const Type* ownerType; // 属性类型,注意是修饰类型
const QualifiedType fieldType; // 是否为类属性
bool isStatic;
}; // 方法
class Method {
// 方法名
std::string name; // 返回类型
const QualifiedType returnType = nullptr; // 所属的类
const Type* ownerType = nullptr; // 参数列表
std::vector<QualifiedType> paramTypes; // 是否为类方法
bool isStatic;
};
通过在类声明中插入代码来注册类型信息,并大量使用模板和宏来简化代码,以 Constructor 为例,其实现如下:
template<class T, class... Args>
class ConstructorImpl : public Constructor {
private:
const Type* type; public:
ConstructorImpl()
: Constructor(typeof(T), { GetQualifiedType<Args>::Value() ... }) {
static_assert(std::is_constructible<T, Args...>::value, "tried to register an undeclared constructor");
} virtual Any Invoke(typename AsType<Args, Any>::Value... params) const override {
return (Any)new T(std::forward<Args>((Args)params)...);
}
};
注册方法信息的实现类似这样:
template<class OwnerType, class ReturnType, class... Args>
const Method* make_method(const std::string& name, ReturnType(OwnerType::*fun)(Args...)){
return new MemberMethod<OwnerType, ReturnType, Args...>(name.substr(name.find_last_of(':') + ), fun);
} #define METHOD(fun) make_method(#fun, fun)
使用示例
下面演示了反射的枚举定义,和反射类型信息的描述
REFLECT_ENUM(Sex, Male, Female) class PhoneNumber{
BEGIN_TYPE(PhoneNumber)
FIELDS(FIELD(&PhoneNumber::areaCode), FIELD(&PhoneNumber::number))
CTORS(DEFAULT_CTOR(PhoneNumber), CTOR(PhoneNumber, const std::string&, const std::string&))
METHODS(METHOD(&PhoneNumber::ToString))
END_TYPE
public:
std::string areaCode;
std::string number; PhoneNumber() {}
PhoneNumber(const std::string& areaCode, const std::string& number) : areaCode(areaCode), number(number) {} std::string ToString() const { return areaCode + " " + number; }
}; class Person{
BEGIN_TYPE(Person)
FIELDS(FIELD(&Person::name), FIELD(&Person::sex), FIELD(&Person::phoneNumber), FIELD(&Person::totalNumber))
CTORS(DEFAULT_CTOR(Person), CTOR(Person, const std::string&, float, Sex))
METHODS(METHOD(&Person::Name), METHOD(&Person::GetSex), METHOD(&Person::GetPhoneNumber), METHOD(&Person::SetPhoneNumber), METHOD(&Person::GetTotalNumber))
END_TYPE
protected:
std::string name;
Sex sex;
PhoneNumber phoneNumber;
static int instanceCount; public:
Person() { totalNumber++; } std::string& Name() { return name; }
Sex GetSex() const { return sex; }
const PhoneNumber& GetPhoneNumber() { return phoneNumber; }
void SetPhoneNumber(const PhoneNumber& phoneNumber) { this->phoneNumber = phoneNumber; }
static int GetInstanceCount() { return instanceCount; }
}; int Person::instanceCount = ;
然后可以像下面这样使用
// 利用反射可以实现通用的 json/xml 转换
auto p = JsonParser::Parse<Person>(R"(
{
"name": "John",
"sex": "Female",
"phoneNumber": { "areaCode": "+86", "number": "" }
}
)"); // 通过反射调用构造方法
auto newPhone = Type::GetType("PhoneNumber")->GetConstructor({qualified_typeof(const std::string&), qualified_typeof(const std::string&)})->Invoke(std::string("+86"), std::string("")); // 调用带参数的方法
p->GetType()->GetMethod("SetPhoneNumber")->Invoke(p.get(), newPhone); // 调用类方法
int instanceCount = typeof(Person)->GetMethod("GetInstanceCount")->Invoke(nullptr); // 获取属性值
Sex sex = p->GetType()->GetField("sex")->Get(p.get()); // 获取枚举值的名字
std::cout << Enum::GetName(sex) << std::endl; // 输出所有属性的名字
for (auto f : typeof(Person)->GetFields()){
std::cout << f->GetName() << "," << std::endl;
}
不足之处
- 由于大量使用模版技术,会导致代码膨胀
- 侵入式的声明方式,必须对现有代码做改动才能使用,如果不需要运行时类型信息,可以改进成在一个单独的初始化方法里进行注册
Demo 地址
Github: https://github.com/Sleen/cpp_reflection
c++ 反射类型的更多相关文章
- WCF XmlSerializer GetType 反射类型 报错 解决方案
为图省事,用现有的EF,和web一起使用一个Model类 当进行到 XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); 会报 ...
- C# 核心语法-反射(反射类型、方法、构造函数、属性,实现可配置可扩展,完成数据库访问类反射封装)
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类.结构.委托.接口和枚举等)的成员和成员的信息.有了反射,即可对每一个类型了如指掌.另外我还可以直接创建对象,即使 ...
- C#—反射(反射类型、方法、构造函数、属性、实现可配置可扩展、数据库访问类反射封装)
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类.结构.委托.接口和枚举等)的成员和成员的信息.有了反射,即可对每一个类型了如指掌.另外我还可以直接创建对象,即使 ...
- Go part 7 反射,反射类型对象,反射值对象
反射 反射是指在程序运行期间对程序本身进行访问和修改的能力,(程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时,程序无法获取自身的信息) 支持反射的语言可以在程序编 ...
- C#反射与特性(三):反射类型的成员
目录 1,获取类型的信息 1.1 类型的基类和接口 1.2 获取属性.字段成员 上一篇文章中,介绍如何获取 Type 类型,Type 类型是反射的基础. 本篇文章中,将使用 Type 去获取成员信息, ...
- java基础之反射类型Type
Java在加入泛型之后,仅仅Class已经不足以描述数据的类型了,比如List<String>类型的数据,其Class的类型为List.class,但是其类型包含了泛型参数,所以java引 ...
- C#反射机制 Type类型
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System ...
- c#反射机制学习和利用反射获取类型信息
反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...
- C#反射与特性(五):类型成员操作
目录 1,MemberInfo 1.1 练习-获取类型的成员以及输出信息 1.2 MemberType 枚举 1.3 MemberInfo 获取成员方法并且调用 1.4 获取继承中方法的信息(Decl ...
随机推荐
- 06JavaScript变量
JavaScript 变量 变量是用于存储信息的"容器". var x=5; var y=6; var z=x+y; 就像代数那样 x=5 y=6 z=x+y 在代数中,我们使用字 ...
- 在IOS端点击数字后会调起系统拨号界面
在IOS端点击数字后会调起系统拨号界面,解决方案: <meta name="format-detection" content="telephone=no" ...
- PHP二维码生成
原文链接:http://www.qqdeveloper.com/detail/14/1.html 代码下载地址:链接:http://pan.baidu.com/s/1dFgqiaP 密码:lex5 材 ...
- day 13 内置函数
内置函数思维导图:https://www.processon.com/view/link/5c13ad2de4b0ed122da75668 内置函数 作用域相关: locals() 返回当前作用域 ...
- ElasticSearch 集群安装,简单使用
http://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html https://gith ...
- Spark 加载数据库mysql表中数据进行分析
1.工程maven依赖包 <properties> <spark_version>2.3.1</spark_version> <!-- elasticsear ...
- 关于org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z报错
之前一直出现这个错误,使用的开发工具是IDEA 我感觉似乎是hadoop与windows的操作系统不太适合 于是在project创建 org.apache.hadoop.io.nativeio包,将N ...
- 20190112-自定义实现字符串的操作方法,如strip,upper,title,ljust,center,zfill,find,rfind等
1:自定义实现strip()Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列算法:strip()仅移除首尾的指定字符,不能移除中间的先从首部开始移除 de ...
- 『Linux基础 - 4 』linux常用命令(1)
这篇笔记包含以下知识点: 几个概念的理解:Linux命令,控制台,终端, 终端提示符 对文件目录的操作的相关命令: 切换目录,列出目录下的文件等 对文件的操作的相关命令: 创建,删除,复制,修改,移动 ...
- CSS-cascading stle sheets
CSS-cascading stle sheets 1. CSS 什么是CSS?CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式 ...