如何找到对象的祖先类型?

How to find types of an object's ancestors?

本文关键字:祖先 类型 对象 何找      更新时间:2023-10-16

我正在创建一种机制,通过该机制,接收方可以告诉发送方每个接收方都对特定类型的消息感兴趣。在下面的示例实现中,存在一个限制,即想要接收特定基类型的所有消息的接收方只接收该类型的显式消息,而不会接收派生类型的消息(例如,请参阅main())。

一个潜在的解决方案是在注册特定消息时注册消息的所有祖先类型,并使用该信息正确路由消息。

还有什么其他解决方案

注意:事实上,我会存储RTTI,这样就不需要每次都查找RTTI了。我在这里也省略了一些其他内容。为了简洁起见,我将使用这个例子。。。

下面的示例代码:

class Sender
{
  typdef std::vector<Receiver const & > Receivers;
public:
  void register(Receiver const & i_recv, typeinfo const & i_type)
  {
    m_routingMap[i_type].push_back(i_recv);
  }

  void send(BaseMsg const & i_msg)
  {
    Receivers receivers = m_routingMap.find(typeid(i_msg));
    for (Receivers::iterator receiver = receivers.begin(); receiver != receivers.end(); ++receiver) {
      receiver.receive(i_msg);
    }
  }
private:
  std::map<typeinfo const &, Receivers> m_routingMap;
};

class Receiver
{
public:
  void receiver(BaseMsg const & i_msg)
  {
    // React to expected messages here
  }
};

class BaseMsg {};
class ChildMsg : public BaseMsg {};
int main()
{
  Sender sndr;
  Receiver recv1;
  sndr.register(recv1, typeid(BaseMsg));
  Receiver recv2;
  sndr.register(recv2, typeid(ChildMsg));
  BaseMsg baseMsg;
  sndr.send(baseMsg); // I want only recv1 to receive this message
  ChildMsg childMsg;
  sndr.send(childMsg); // I want both Receivers to receive this message, but only recv2 will receive it
}

更新:这是我正在讨论的解决方案:

// Note: implementation is based in gleaning from
// http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
class BaseMsg
{
public:
  typedef std::vector<TypeInfo const & > Types;
  static TypeInfo const * getType()
  {
    TypeInfo static * ms_type = new TypeInfo(typeid(BaseMsg));
    return ms_type;
  }
  static Types const * getAncestorTypes()
  {
    // The base class does not have an ancestor
    // Static varible, will only be constructed once!
    Types * ms_ancestorTypes = new Types();
    return ms_ancestorTypes;
  }
};

class ChildMsg
{
public:
  static TypeInfo const * getType()
  {
    TypeInfo static * ms_type = new TypeInfo(typeid(ChildMsg));
    return ms_type;
  }
  static Types const * getAncestorTypes()
  {
    // Add the parent type and all the parent's ancestor's types
    Types const * ancestorTypes = BaseMsg::getAncestorTypes();
    // Static variable, so it will only be constructed once!
    Types * static ms_ancestorTypes = new Types(ancestorTypes->begin(), ancestorTypes->end());
    // This push_back() will occur every time, but it's only one operation,
    // so hopefully it's not a big deal!
    ms_ancestorTypes->push_back(BaseMsg::getType());
    return ms_ancestorTypes;
  }
};

发件人:

# Python pseudo code
class Sender:
  def send(self, i_msg):
    types_to_check_for = [i_msg.getType()].extend(i_msg.getAncestorTypes())
    for type_ in types_to_check_for:
      for receiver in _routing_list[type_]:
        receiver.receive(i_msg)

也许可以考虑使用观察者模式(http://en.wikipedia.org/wiki/Observer_pattern)。

通过这种方式,你的发送者不知道你的接收者,你的观察者可以控制消息的分发。

发件人->通知观察者有消息。

observer->通知每个感兴趣的方有一个新的消息。

感兴趣的部分->做有趣的事情。

这将需要某种消息识别系统。也许所有的msg都可以继承自一个具有type成员和id成员的msg类型。这样你就可以使用它们注册消息了。

更新:

一种快速消息结构:

class Message
{
public:
    size_t m_Type;
    size_t m_Id;
protected:
    Message(size_t type, size_t id) : m_Type(type), m_Id(id) {}
};
class Type1 : public Message
{
public:
    static const size_t type = 1;
    Type1(size_t id) : Message(type, id) {}
};

订阅者是指想要收听消息的人)。订阅者应该有一个接口来接受基于这两个功能的消息。

Class subscriber
{
    virtual void receiveType(size_t type, char * data) = 0;
    virtual void receiveMsg(size_t type, size_t id, char * data) = 0;
};

观测者应该有一个注册消息的方法:

Class Observer
{
void registerForType(type, subscriber);
void registerForMsg(type, id, subscriber);
};

另一个更新:

这实际上只是一个概念的粗略证明。一个人可以在不知道确切祖先链的情况下做你想做的事。请原谅触发器和registrationEntry函数的切换(一开始我做错了,这是最简单的更正,再次证明了概念)。这个草图的另一个缺点是,至少必须构造一个msg才能注册。如果你正在寻找一个真正的长期解决方案,我建议你找到一个已经有反射的库或框架(例如QT有元对象),这些可以用来查看超类。或者,您可以使用已经存在的信号/插槽。

以下代码的输出:

正在启动C:\Users\David\Downloads\asdf-build-desktop-Qt_4_8_0_for_desktop_-MinGW_Qt_SDK__Release\Release\asdf.exe…
基址寄存器
注册:BaseMsg
子寄存器
注册:消息
基本呼叫
触发器:BaseMsg
虚拟void Subscriber1::newMessage(const BaseMsg&)
Der。呼叫
触发器:BaseMsg
虚拟void Subscriber1::newMessage(const BaseMsg&)
触发器:消息
虚拟void Subscriber2::newMessage(const BaseMsg&)
C: \Users\David\Downloads\asdf-build-desktop-Qt_4_8_0_for_desktop_-MinGW_Qt_SDK__Release\Release\asdf.exe退出,代码为0

#include <string>
#include <vector>
#include <map>
#include <stdio.h>
using namespace std;
class BaseMsg
{
public:
    BaseMsg()
    {
        theRealInit();
    }
    //incase you don't want to go all the way down the rabbit hole.
    //At the bottom they are the same
    virtual vector<string> const & registrationEntries() const  {return m_SubClassChain;}
    virtual vector<string> const & triggerEntries() const       {return m_SubClassChain;}
    protected:
    virtual void init() { printf("Should NOT CALL THIS HERE!");}
    vector<string> m_SubClassChain;
private:
    void theRealInit()
    {
        m_SubClassChain.push_back("BaseMsg");
    }

};
class Message : public BaseMsg
{
    public:
    Message() : BaseMsg()
    {
        init(); //MUST BE CALLED from child
    }
    virtual vector<string> const & triggerEntries() const       {return m_TriggerEntries;}
protected:
    virtual void init()
    {
        //BaseMsg::init();
        m_SubClassChain.push_back("Message");
        m_TriggerEntries.push_back("Message");
    }
private:
    vector<string> m_TriggerEntries;
};
class Subscriber
{
public:
    virtual void newMessage(BaseMsg const & i_msg)
    {
        printf("%sn", __PRETTY_FUNCTION__);
    }
};
class Subscriber2 : public Subscriber
{
public:
    virtual void newMessage(BaseMsg const & i_msg)
    {
        printf("%sn", __PRETTY_FUNCTION__);
    }
};
class Subscriber1 : public Subscriber
{
public:
    virtual void newMessage(BaseMsg const & i_msg)
    {
        printf("%sn", __PRETTY_FUNCTION__);
    }
};

class Sender
{
  //typdef vector<Receiver const & > Receivers;
public:
    void registerForMsg(Subscriber * someoneThatCares, BaseMsg const & msg)
    {
        vector<string> const & triggers = msg.triggerEntries();
        vector<string>::const_iterator it = triggers.begin();
        for(; it != triggers.end(); it++)
        {
            printf("Registration: %sn", it->c_str());
            m_routingMap.insert(pair<string, Subscriber *>(*it, someoneThatCares));
        }
    }

  void send(BaseMsg const & msg)
  {
      vector<string> const & triggers = msg.registrationEntries();
      vector<string>::const_iterator it = triggers.begin();
      for(; it != triggers.end(); it++)
      {
          printf("Trigger: %sn", it->c_str());
          pair<multimap<string, Subscriber *>::iterator, multimap<string, Subscriber *>::iterator> ret;
          //borrowed from: http://www.cplusplus.com/reference/stl/multimap/equal_range/
          ret = m_routingMap.equal_range(*it);
          multimap<string, Subscriber *>::iterator it1;
          for (it1 = ret.first; it1 != ret.second; ++it1)
          {
              it1->second->newMessage(msg);
          }
      }
  }
private:
  multimap<string, Subscriber *> m_routingMap;
};
int main(int argc, char *argv[])
{
    Sender sndr;
    BaseMsg baseMsg;
    Message message;
    printf("Base Registern");
    Subscriber1 recv1;
    sndr.registerForMsg(&recv1, baseMsg);
    printf("Child Registern");
    Subscriber2 recv2;
    sndr.registerForMsg(&recv2, message);

    printf("Base calln");
    sndr.send(baseMsg); // I want only recv1 to receive this message
    printf("Der. calln");
    sndr.send(message); // I want both Receivers to receive this message, but only recv2 will receive it
    return 0;
}