来自:

实现代码===

//
// 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++11 reflection library

RTTR 库

Boost.Mirror 库

Mirror C++ reflection library

本文讨论如何在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++ 反射类型的更多相关文章

  1. WCF XmlSerializer GetType 反射类型 报错 解决方案

    为图省事,用现有的EF,和web一起使用一个Model类 当进行到 XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); 会报 ...

  2. C# 核心语法-反射(反射类型、方法、构造函数、属性,实现可配置可扩展,完成数据库访问类反射封装)

    反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类.结构.委托.接口和枚举等)的成员和成员的信息.有了反射,即可对每一个类型了如指掌.另外我还可以直接创建对象,即使 ...

  3. C#—反射(反射类型、方法、构造函数、属性、实现可配置可扩展、数据库访问类反射封装)

    反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类.结构.委托.接口和枚举等)的成员和成员的信息.有了反射,即可对每一个类型了如指掌.另外我还可以直接创建对象,即使 ...

  4. Go part 7 反射,反射类型对象,反射值对象

    反射 反射是指在程序运行期间对程序本身进行访问和修改的能力,(程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时,程序无法获取自身的信息) 支持反射的语言可以在程序编 ...

  5. C#反射与特性(三):反射类型的成员

    目录 1,获取类型的信息 1.1 类型的基类和接口 1.2 获取属性.字段成员 上一篇文章中,介绍如何获取 Type 类型,Type 类型是反射的基础. 本篇文章中,将使用 Type 去获取成员信息, ...

  6. java基础之反射类型Type

    Java在加入泛型之后,仅仅Class已经不足以描述数据的类型了,比如List<String>类型的数据,其Class的类型为List.class,但是其类型包含了泛型参数,所以java引 ...

  7. C#反射机制 Type类型

    using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System ...

  8. c#反射机制学习和利用反射获取类型信息

    反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...

  9. C#反射与特性(五):类型成员操作

    目录 1,MemberInfo 1.1 练习-获取类型的成员以及输出信息 1.2 MemberType 枚举 1.3 MemberInfo 获取成员方法并且调用 1.4 获取继承中方法的信息(Decl ...

随机推荐

  1. 用RestTemplate调取接口,取得返回数据,携带header,动态拼接url ,动态参数

    记录我自己的工作 get 请求  ,携带 请求头 header (token) url 根据参数 动态拼接 参数   放入 map  动态拼接 private String lclUrl = &quo ...

  2. 解决jquey中当事件嵌套时,内层事件会执行多次的问题

    出现情景:当内层事件需要外层事件触发后产生的一些值得时候 情景复现: <!DOCTYPE html> <html lang="en"> <head&g ...

  3. Linux中Zookeeper部署和集群部署

    自己网上下载安装包,我下载的是tar.gz安装包直接解压,也可以下载rpm格式 1.下载zookeeper安装包,放到/usr/local/zookeeper安装包网上下载 2.解压文件tar -zx ...

  4. xshell安装教程

    Xshell安装使用教程 Xshell 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议.Xshell 通过互联网到远程主机 ...

  5. 初学者:__init__.py文件的作用

    __init__.py 文件的作用及意义 __init__.py文件是一个包必须的文件,即使它是空的,但也是必须的,如果没有这个文件,python将不会把该文件夹当做一个package,而仅仅是一个d ...

  6. Python的scrapy之爬取顶点小说网的所有小说

    闲来无事用Python的scrapy框架练练手,爬取顶点小说网的所有小说的详细信息. 看一下网页的构造: tr标签里面的 td 使我们所要爬取的信息 下面是我们要爬取的二级页面 小说的简介信息: 下面 ...

  7. Python 爬虫 七夕福利

    祝大家七夕愉快 妹子图 import requests from lxml import etree import os def headers(refere):#图片的下载可能和头部的referer ...

  8. A1041

    输入n个数,找出第一个只出现一次的数,输出它. 如果没有,输出none. 思路: 将输入的数值作为HashTable的数组下标即可. #include<cstdio> ], hashTab ...

  9. BZOJ3209(luogu 4317)花神的数论题题解

    题目 设 sum(i) 表示 i 的二进制表示中 1 的个数.给出一个正整数 N ,花神要问你 派(Sum(i)),也就是 sum(1)—sum(N) 的乘积(n<=1e15). 分析 好吧,一 ...

  10. 【blockly教程】第四章 Blockly之选择结构

    今天,我们通过一个游戏来学习选择结构,游戏的地址如下:https://blockly-games.appspot.com/bird?lang=en本游戏分为10关:主要游戏规则如下:①主界面是游戏的运 ...