0

这是我的消息结构:

struct tEventMessage 
{
    // Type of the event
    int Type;

    // (void*) Allows those to be casted into per-Type objects
    void *pArgument1;   
    void *pArgument2;

};

我可以在这个结构中添加某种“模板”成员,以便稍后在构建消息时我可以传递这些指针 + 和我希望的任何其他数据?(见下面的例子)

struct tEventMessage 
{
    // Type of the event
    int Type;

    // (void*) Allows those to be casted into per-Type objects
    void *pArgument1;   
    void *pArgument2;

    // Template
    T tSomeTemplateMember;
};

 void HandleClick(....)
 {
 CVector3 vNewPosition = ....

 tEventMessage _msg;
 _msg.Type = xxxx;
 _msg.pArgument1 = pA->GetObjectPointer();

 //
 // Wrong!
 // Because this CVector3 will not be alive in next tick
 // - my pointer will point to nothing.
 //
 _msg.pArgument2 = static_cast<CVector3*>(&vNewPosition)


 //
 // Something like that would be great
 // And would allow me to use CVector2,CVector3,CVector4 with one template member
 // 
 _msg.tSomeTemplateMember = vNewPosition;

 }
4

2 回答 2

2

我认为你把问题复杂化了。您现在有两个问题,即如何在消息中传递任意数据,而不是一个问题,即如何处理模板。

实现这种事情的常用方法是使用继承:-

class Message
{
public:
  int Type () { return type; }
protected:
  int type;
};

class ClickMessage : public Message
{
public:
  ClickMessage () { type = ClickMessageID; }
private:
  // the message data
};

void HandleMessage (Message *message)
{
  switch (message->Type ())
  {
  case ClickMessageID:
    HandleClick (reinterpret_cast <ClickMessage *> (message));
    break;
  default:
    // unhandled message error
    break;
  }
}

void HandleClick (ClickMessage *message)
{
  // do stuff
}

问题是你最终会重复很多代码,即 switch 语句中的强制转换。还有一个维护问题 - 添加新消息需要仔细更新。您可以稍微修改一下代码并使用函数指针和映射将消息类型转换为函数并替换 switch 语句。

可能有一个聪明的模板解决方案,但我想不出它可能是什么。

使用 RTTI 可能会有所帮助(需要付出代价)。

这是反射真正擅长解决的问题之一!

于 2012-11-01T21:37:03.897 回答
1

也许我遗漏了一些东西,但是我想知道为什么您不从抽象类开始,然后从中派生各种事件消息。通过利用抽象类并从它们派生类,您可以让编译器找出您使用 switch 语句的逻辑。请参阅此C++ 多态性和抽象基类教程

另请参阅MSDN 关于 Abstract classes 的内容

例如,您可能有一个如下所示的抽象类。但是,您可能不想要这么多,实际上可能只需要单一processEvent()方法。任何派生类都需要为抽象类中指定的每个函数提供它们自己的版本。

class EventMessage abstract {
public:
    virtual void *getArgument1 (void) = 0;
    virtual void *getArgument2 (void) = 0;
    virtual int   processEvent (void) = 0;
protected:
    void *pArgument1;
    void *pArgument2;
};

这个抽象类定义的是一个基本上包含所有各种事件消息使用的数据的类,以及一个被调用来处理实际消息的方法。类本身没有被实例化,但是它被用作实际实例化为对象的其他派生类的父类或超类。

然后您要做的是派生将实现 EventMessage 接口的新类。例如,这里有两个不同的类可以做到这一点:

class JoJoEvent : public EventMessage {
public:
    JoJoEvent(void *arg1, void *arg2);
    void *getArgument1 (void);
    void *getArgument2 (void);
    int   processEvent (void);
};
JoJoEvent::JoJoEvent(void *arg1, void *arg2)
{
    pArgument1 = arg1;
    pArgument2 = arg2;
}

void * JoJoEvent::getArgument1 (void) {
    return pArgument1;
}
void * JoJoEvent::getArgument2 (void) {
    return pArgument2;
}

int JoJoEvent::processEvent (void) {
    // do stuff with the arguments
    return 1;
}

class KoKoEvent : public EventMessage {
public:
    KoKoEvent(void *arg1, void *arg2);
    void *getArgument1 (void);
    void *getArgument2 (void);
    int   processEvent (void);
};
KoKoEvent::KoKoEvent(void *arg1, void *arg2)
{
    pArgument1 = arg1;
    pArgument2 = arg2;
}

void * KoKoEvent::getArgument1 (void) {
    return pArgument1;
}
void * KoKoEvent::getArgument2 (void) {
    return pArgument2;
}

int KoKoEvent::processEvent (void) {
    // do stuff with the arguments
    return 1;
}

然后在使用这些时,您将执行类似以下代码的操作:

EventMessage *myMessage = new JoJoEvent(0, 0);

EventMessage *myMessage2 = new KoKoEvent(0, 0);

myMessage2->processEvent();
myMessage->processEvent();

如果您需要将其他数据添加到派生类中,您只需提供一种将数据放入派生类的机制即可。

于 2012-11-01T23:13:00.070 回答