原生C++中的数据驱动设计
Data Driven Design in native C++
所以我正在编写一个游戏引擎,它利用数据驱动的设计来实例化xml文件中的各种Actor。 我最近完成了事件管理系统的编码,所有内容都会触发事件,处理程序会正确捕获它们。 考虑到我使用了成员函数指针和模板,这不是一件容易的事。 我现在遇到的问题是我希望能够在 xml 文件中做这样的事情:
<InputComponent>
<Event EventName="GainedFocus" OnEvent="Initialize"/>
</InputComponent>
问题应该很明显。C++没有形式的反射,因此据我所知,无法从字符串"初始化"中获取 Initialize 函数的地址。 这意味着对于略有不同的输入组件,我从类派生并注册特定于该实例的事件并添加函数。 另外,应该知道这与我处理典型输入的方式不同:
<InputComponent>
<Mapping Type="MousePress" Button=1 Command="RotateCamera"/>
</InputComponent>
在此实例中,映射是特定于输入组件的元素,命令本身是使用工厂创建的对象。 不过,我无法真正对通用事件执行此操作。 命令是对不同对象执行完全相同操作的特定项,而对象或组件本身通常需要以不同的方式处理单个事件。 以前有人做过这样的事情吗? 真的很好奇有人如何去做这样的事情,以便需要注册到对象的事件不必硬编码到类本身中。
编辑:让我这样说。 相同类型组件的不同实例需要对事件做出不同的反应。 这将是特定于应用程序的,因此应该与引擎代码分开(我不应该修改组件)。 用户应该能够提供函数,然后可以在对事件做出反应时调用这些函数。 函数和事件都应该能够在 XML 中绑定。 我开始认为这在非托管C++中可能是不可能的,因为没有形式的元数据来查找用户基于同名字符串提供的函数。
可以使用将字符串与函数指针相关联的映射。
或者,如果函数签名不同,则可以使用带有 if-else-if 梯形图的工厂模式。
编辑 1:示例
// Typedef for event functions
typedef void (*Event_Function_Pointer)(const Event& e);
typedef std::map<std::string, Event_Function_Pointer> Event_Function_Container;
//...
Event_Function_Container events;
events["Gained Focus"] = Initialize;
还有一个选项是查找表,因为文本和函数指针是常量数据:
struct Event_Function_Entry
{
char * const * event_name;
Event_Function_Pointer event_function;
};
Event_Function_Entry events[] =
{
{"Gained Focus", Initialize},
};
您的组件都可以从同一个基继承,该基库为命令将调用的基本操作提供了接口:
class Component {
public:
virtual void initialize();
virtual void rotate(int x, int y);
...
};
class Monster : public Component {
virtual void initialize(); // concrete implementation for a Monster
virtual void rotate(int x, int y);
};
然后,您可以考虑"命令"设计模式。 一般思路是:
class Command { // generic interface for commands
Component *receiver;
public:
Command(Component *receiver);
virtual ~Command();
virtual void execute();
};
class InitializeCommand : Command { // a specific command
public:
InitializeCommand (Component *receiver /* + additional command specific parameters */); // specific constructor with all needed parameters
void execute() {
// use the parameters and do the common operations
receiver->initialize(); // polymorphically call the object operations
// ...
}
};
其余的取决于您的全局设计。
例如,您可以设计一个工厂,该工厂将根据处理的事件创建命令并执行这些命令:
if (event==...) {
// todo: find object pointed to by the object
Command c = myfactory_for_event (object, parameters);
c.execute();
}
如果您的 xml 文件用于配置对象,则读取该文件,创建特定命令,并将它们存储在将事件名称与具体命令相关联的事件映射中:
map<string,Command*> commands;
在这种情况下,事件处理将如下所示:
myobject["initialize"]->execute();
所以没有人知道是否有办法做到这一点?显然有黑客方法。 多个集成,多个工厂等。 我只能将事件的响应作为命令对象完成,但这似乎是一个奇怪的解决方案......因为没有可用的运行时信息,我必须将每个 INDIVIDUAL 函数封装在自己的类中。如果你问我,浪费内存...才意识到这听起来有多奇怪。基本上,我的意思是对于我想映射到事件的每个功能,我必须创建一个全新的类(与我已经用于映射键的命令模式相同)。 如果我能提供一个函数地址,而不是为单个操作分配和解除分配内存,那会容易得多,但似乎没有人有答案。
- Mongodb c++驱动程序:如何查询元素的数组
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 员工测试驱动程序数据结构
- 为 Sql 服务器实现 odbc 包装器.将数据库数据读取为字符或要求驱动程序将数据转换为 C 类型
- Boost 的数据驱动测试的联接运算符"+"损坏了第一列
- 如何使用 C++ 驱动程序在 MongoDB 中使用 UserException 处理数据类型错误
- 在c++中创建数据驱动的结构
- 如何使用 MSTest 为C++测试设置数据驱动测试
- 原生C++中的数据驱动设计
- 运行select语句时,Firebird ODBC驱动程序数据被截断
- 使用RtlCopyMemory在驱动程序中复制数据
- TAEF数据驱动的c#应用程序在windows phone上
- 数据驱动的单元测试与谷歌测试
- 数据驱动的测试不好吗?
- 如何将数据从内核模式驱动程序发送和接收到用户模式下的二进制文件
- 语言和数据库适合数据驱动的游戏,如足球经理
- 新的c++ 11驱动程序-如何从二进制数据创建文档
- 如何在开发数据驱动的渲染器时处理 API 差异
- 如何捕获和控制发送到OPOS打印机驱动程序的数据流