何谓反射?
我在工作中大量使用了 google protocal buffer, 为了方便描述, 下文简称为 pb. pb 的作用和基本使用方法在这里就不再陈述, 相关的文章网上很多. 这里主要介绍 pb 的反射机制.
什么是反射机制呢? 该机制能在运行时, 对于任意一个类, 都能知道这个类的所有属性和方法; 对于任意一个对象, 都能调用它的任意一个方法和属性; 简言之, 反射机制使程序员可以动态获取对象信息以及动态调用对象的方法. 下面用两个例子来解释什么是反射.
1. 动态获取对象信息
对于一个 c++ 类 Player , 如果标准提供一个函数 Show(Player), 可以取到 Player 的所有成员函数和变量的名字. 我们就说 Show 函数可以动态获取对象的信息.
2. 动态调用对象的方法.
Player 类里有一个函数 AddMoney(int a), playerA 是一个Player 对象. 如果标准提供一个函数 Call(playerA, "AddMoney", 100), 能达到 playerA.AddMoney(100) 相同的效果. 我们就说 Call 函数可以动态调用对象的方法.
当然, c++ 没有 Show 和 Call 这两个函数, 所以c++不具备反射机制. 提供了 Show 和 Call, 或是能达到同样功能的函数的系统, 就实现了反射机制.
pb 的反射
知道了什么是反射, 我们来看看 pb 是如何实现的. 首先认识几个关键类.
google::protobuf::Message
这是用户自定义消息的基类. 系统会为给每个用户自定义消息实例化一个默认对象, 对象用 Message* 保存.
Message 类定义了 New() 虚函数, 可以返回本对象的一份新的实例, 类型和本对象的真实类型相同. 拿到了 Message*, 不用知道它的具体类型, 就可以创建和它一样类型的对象. 通过 New() 函数创建的对象, 需要用户自己释放. New() 函数是线程安全的.
google::protobuf::MessageFactory
管理所有自动实例化的 Message 对象. 它自身也会被自动实例化, 通过静态函数
generated_factory() 能拿到该对象指针. 通过成员函数
GetPrototype() 能拿到自动实例化的 Message*; GetPrototype() 的参数是一个 Descriptor*; MessageFactory 是线程安全的.
google::protobuf::Descriptor