在C++中利用全局对象的构造函数实现反射机制
1. 反射机制
Java语言中,对于任意一个类在运行状态下,都能够知道这个类的所有属性和方法;对于任意一个类的实例,也都能够调用它的任意方法和属性;这种动态获取类的信息以及动态调用对象方法的功能称为反射机制。
反射机制在我们日常的编程当中应用的不是很多,但是在设计模式中反射一个非常强大的工具。尤其是在设计模式中的工厂模式中,在工厂类中反射机制的使用可以免除switch case繁杂编写和维护。通过反射,可以方便的通过字符串指定类名从而创建出具体的产品类。但是在C++中,类的生成是要完完全全在编译时指定的。它无法像Java一样在运行时动态的创建对象。因此在增加产品类时将无可避免修改工厂类,这不是我们所希望看到的。一旦修改,就意味着要重新进行测试。
因此,为了使得C++更易于修改并且减少测试的工作量。本文将使用全局对象的构造函数来实现一定程度的反射机制。
2. 方法概述
由于C++语言的特性,任何对象的创建在编译期都必须进行明确。所以为了实现一定程度的反射,本文所述方法的主要结构就是在程序 Main 函数之前将所有的类的信息注册到一个数据结构中。这样在 Main 函数开始运行之后就可通过访问该数据结构获取全部类的信息。
由于C++是不允许在函数体外进行语句编写的,如何在 Main 函数运行之前构建好所有类的信息库是主要需要解决的问题。因此全局对象的构造函数恰好可以满足我们的需要。全局对象生命周期作用于整个程序的运行期,因此全局对象的内存分配和初始化都在程序正式运行之前。
3. 引入反射机制的简单工厂模式
3.1 工厂类
3.1.1 a_factory.h文件
#ifndef _A_FACTORY_
#define _A_FACTORY_
#include "a_interface.h"
#define REGISTER_TO_A_FACTORY(PRDT, PRDT_NAME) \
PRDT reg_##PRDT; \
a_factory fty_##PRDT(PRDT_NAME, (a_interface *)®_##PRDT);
class a_factory
{
public:
a_factory(const char *name, a_interface *obj);
public:
static a_interface * get_a(const char *name);
};
#endif
宏 REGISTER_TO_A_FACTORY 用于将产品类注册到该工厂中。从宏的定义中可以看出,对于每一个产品类申明了一个该产品类的全局对象。并将该全局产品对象的地址和产品名作为构造函数的参数又申明了一个全局工厂对象。该工厂对象负责该产品对象的注册。注册的具体实现见 3.1.2。
静态成员函数 get_a 用于通过指定注册的子类(产品)名从而获得子类对象(该产品)。
3.1.2 a_factory.cpp
#include "a_factory.h"
#include <iostream>
#include <cstring>
using namespace std;
static struct {
char name[128] = {
0};
a_interface *ptr = NULL;
} registation[100];
static int reg_idx = 0;
a_factory::a_factory(const char *name, a_interface *obj)
{
string key(name);