我目前正在将游戏引擎作为大学模块的一部分,其中一部分是消息处理系统。我正在寻求改进讲师的实施方式,因此,对我可能做出的任何更改提出任何建议或批评是最欢迎的。
当前消息结构
struct Message
{
Entity* entity;
std::string message;
void* data;
Message(Entity* entity, std::string message, void* data):
entity(entity), message(message), data(data) {}
};
最初的实现只将消息发送到实体,但是我计划使用“接口”来允许游戏引擎的任何组件都能够接收消息。
class IMessageReceiver
{
public:
virtual void handleMessage(const Message& message) {}
};
struct Message
{
IMessageReceiver* receiver;
std::string message;
void* data;
};
//examples
class Entity : public IMessageReceiver { };
class Game : public IMessageReceiver { };
当前系统存在的一个问题是数据的void *(我只是不喜欢使用void *)。然后将其强制转换为需要在handleMessage函数内部的类型,因为我知道应该接收什么数据(取决于消息字符串)-到目前为止,通常它是3D矢量或Entity,但是如果我让它向除Entities之外的其他事物发送消息,那么这可能会改变。
我想将其更改为使用模板。但是,我不确定该怎么做。
template <typename T>
struct Message
{
IMessageReceiver* receiver;
std::string message;
T* data;
};
我对模板有一些基本的了解,但是我可能缺乏对模板欺骗的更深入的了解。我知道我可以在创建新消息时将数据类型传递给它。
//example
Entity* entity;
vec3 someVec;
Message<vec3> message(entity, "Fire", someVec);
MessageHandler::sendMessage(message);
但是,由于不同的实现类在发送给它们的消息中具有不同的数据时,该如何在IMessageReceiver中编写handleMessage函数声明?
virtual void handleMessage(const Message<?>& message) {}
我曾想过将IMessageReceiver也作为模板类,所以当类从其继承时,它们将设置接收到的消息的数据类型。
template <typename T>
class IMessageReceiver
{
public:
virtual void handleMessage(const Message<T>& message) {}
};
class Entity : IMessageReceiver<vec3> {};
但是,这意味着消息接收者只能接收一种类型的信息,但是在某些情况下,我可能不得不将不同类型的数据发送到同一接收者,例如,实体的派生类通常接收vec3作为消息的数据部分,但是新场景要求它接收另一个实体。我发现的另一个问题是,只有抽象基类Entity才从IMessageReceiver继承(不是Entity的每个派生类,它们都收到不同类型的信息,也可能),这意味着将Entity也作为模板类,因此可以通过传递来设置。但是我仍然会拥有一个不灵活的系统,其中某些东西只能接收一种数据类型的消息。
也许void *是“最佳”方法,也许不是使用接口类。我不知道。
请随时提出您可以想到的任何建设性批评。我并不是要有人为我编写它,我只是在寻求有关实现我尝试做的一种好方法的建议。基本上,我希望能够使引擎的任何组件都能够接收消息。消息中发送的数据不是预定义的;并且最好不要使用void *。
感谢您抽出时间来阅读。如果您需要任何其他信息,请告诉我。
加文
虚函数要求在编译时就知道确切的签名,因此您不能直接使用“模板欺骗”来实现所需的功能。
看看Boost.Any可以替代void* Message::data
。它仍然需要进行某种类型的转换才能将其转换为正确的类型,但这是以类型安全的方式完成的。同样,通过这种方式,消息“拥有”数据,因此您不必担心生命周期问题。
另外,不要使用IMessageReceiver
,std::function<void(const Message&)>
而是考虑。这样,您可以将消息传递给具有的任何对象void operator()(const Message&)
,而不必担心层次结构的复杂性。
双方boost::any
并std::function
在内部使用所谓的技术型擦除这需要继承了接口,并允许您对待事物的价值观,这往往使代码更简单道理的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句