c++ 反射机制: 用类名作变量,动态创建对象

什么是反射

创建对象的角度上来看,狭义的说,比如有个 class A ,你能直接 new A() 来创建 对象。但是如果想根据字符串 “A” 来创建 class A 的对象,比如 使用 new “A” 的形式来创建 对象,甚至 “A” 是个变量。 str = “A” , new str.

这种把 class 作为变量,又能在运行时创建对象的机制,就叫做反射。

大部分的高级编程语言,先天是支持反射的。用 lua 举例

local AllTypes = {
    Type1 = 1,
    Type2 = 2,
    Type3 = 3,
}

local typeClsHash = {}
typeClsHash[AllTypes.Type1] = Cls1
typeClsHash[AllTypes.Type2] = Cls2
typeClsHash[AllTypes.Type3] = Cls3

local theType = AllTypes.Type2

local cls = typeClsHash[theType]
local instance = cls:new()
instance:doSth()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

如上面的代码,可以动态的通过 theType 变量的值,来选择 new 哪个 class 的对象。这样代码写起来就比较灵活,省去了写一大堆丑陋的 switch case,if/else 。

c++ 代码示例

需求

游戏里面有很多UI,是 BaseMenu 的子类。包括MenuStageSelect, MenuHUD 等等。希望通过 MenuManager::pushMenu() 一个函数,写明 Menu 的类型,动态创建和现实对应的 Menu.

原理

由于c++ 语言先天不支持反射机制,因此这种动态 new 不同 class 的实例的机制,在实现起来,必须依赖于函数指针。
用一个 std::map<>来存储不同类型的Menu 的创建函数,key 是 menu类型,value 是创建的函数指针。
这样才能实现反射机制,动态创建对象。

实现

MenuManager.h 定义所有 BaseMenu子类的枚举

typedef enum
{
    MENU_STAGE_SELECT,
    MENU_HUD,   
}MenuType;
  • 1
  • 2
  • 3
  • 4
  • 5

MenuManager 定义一个 std::map 成员,用于存储哪个类型的 menu ,由哪个函数来负责创建。

// Registered menus
typedef std::function<BaseMenu*()> MenuCreateFuncType;
std::map<MenuType, MenuCreateFuncType> _registerMenus;
  • 1
  • 2
  • 3

每个 Menu 都需要提供自己的创建函数。在对应的类里面,实现一个 static XXX* createInstance() 的方法。

例如 MenuHUD
在 MenuHUD.h 声明 static MenuHUD* createInstance() 函数

class MenuHUD : public BaseMenu
{
public:
    static MenuHUD* createInstance();
  • 1
  • 2
  • 3
  • 4

在 MenuHUD.cpp 里实现它

MenuHUD* MenuHUD::createInstance()
{
    return new MenuHUD();
}
  • 1
  • 2
  • 3
  • 4

每个 BaseMenu 的子类都需要实现这个静态函数。


在游戏初始化时,注册所有 Menu 的创建函数。

void MenuManager::registAllMenus()
{
    _registerMenus[MenuType::MENU_STAGE_SELECT] = MenuStageSelect::createInstance;
    _registerMenus[MenuType::MENU_HUD] = MenuHUD::createInstance;
}
  • 1
  • 2
  • 3
  • 4
  • 5

这些准备工作做完之后,就可以在 MenuManager::pushMenu(MenuType menuType) 函数里,根据 Menu 类型,动态 new 出不同类型的 menu 的实例了。

void MenuManager::pushMenu(MenuType menuType)
{
    BaseMenu* pInstance = _registerMenus[menuType]();
    /*
        Do other things...
    */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面 map 的 key 是 Menu 的枚举。如果希望用 Menu 的类名做变量,只需要把 key 的 枚举,修改为 std::string ,在 registerAllMenus() 里面,用类名作 key 即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值