存储函数指针的任何成员函数(Store Function Pointers to any Membe

2019-07-01 11:32发布

我的事件管理器

对于事件管理器,我需要很多函数指针存储在一个矢量打电话给他们时,该事件被触发。 (我将提供在这个问题的端部的EventFunction辅助类的源代码。)

// an event is defined by a string name and a number
typedef pair<string, int> EventKey;

// EventFunction holds a pointer to a listener function with or without data parameter
typedef unordered_map<EventKey, vector<EventFunction>> ListEvent;

// stores all events and their listeners
ListEvent List;

注册一个监听器可以通过调用第一或第二功能,这取决于如果你想获得更多的数据或不能这样做。 (此代码是从我的事件管理器类。)

public:
  typedef void (*EventFunctionPointer)();
  typedef void (*EventFunctionPointerData)(void* Data);

  // let components register for events by functions with or without data parameter,
  // internally simple create a EventFunction object and call the private function
  void ManagerEvent::Listen(EventFunctionPointer Function, string Name, int State);
  void ManagerEvent::Listen(EventFunctionPointerData Function, string Name, int State);

private:
  void ManagerEvent::Listen(EventFunction Function, string Name, int State)
  {
    EventKey Key(Name, State);
    List[Key].push_back(Function);
  }  

成员函数指针

代码不工作,因为我存储函数指针而不是成员函数指针在我的名单。 所有这些指针应该是成员函数指针,因为像组件ComponentSound会听取事件"PlayerLevelup"与它的成员函数ComponentSound::PlayerLevelup如果触发事件打出一场漂亮的声音。

在C ++中的成员函数指针看起来像这样。

// ReturnType (Class::*MemberFunction)(Parameters);
void (ComponentSound::*PlayerLevelup)();

问题是,任何组件类应该能够侦听事件,但存储成员函数指针在事件管理器需要我指定的听力课。 正如你所看到的例子,我需要指定ComponentSound但事件管理器应该只是有成员函数指针的向量任一类别。

这些问题的一个答复会帮助我很多。

  • 我怎样才能函数指针存储到任何成员函数在我的事件管理器的载体? (也许它可以帮助所有的监听功能,从一个抽象类继承的Component )。
  • 我怎样才能设计出我的事件管理器以另一种方式来达到目的的功能? (我想用字符串和int键的消息。)

我试图让我的问题一般,但如果你需要更多的信息或代码,请发表评论。

分配

在我的成员函数指针的矢量I使用EventFunction代替仅一个指针,以提供两种消息类型。 其中有,一个没有数据参数。

class EventFunction
{
private: EventFunctionPointer Pointer; EventFunctionPointerData PointerData; bool Data;
public:
    EventFunction(EventFunctionPointer Pointer) : Pointer(Pointer), PointerData(NULL), Data(false) { }
    EventFunction(EventFunctionPointerData PointerData) : PointerData(PointerData), Pointer(NULL), Data(true) { }
    EventFunctionPointer GetFunction() { return Pointer; }
    EventFunctionPointerData GetFunctionData() { return PointerData; } bool IsData() { return Data; }
    void Call(void* Data = NULL){ if(this->Data) PointerData(Data); else Pointer(); }
};

Answer 1:

没有一个直接的反应,所以大家多多包涵。

在我们开始之前:这通常被称为Observer模式,你可能会发现很多关于它在网络上的信息混乱,许多失败的实现,但谁知道你还可能打击黄金。

好了,所以首先这个问题有一个根本的缺陷:它没有考虑到拍摄对象的引用是棘手的 ,因为对象的寿命是有界的。

因此,即使在我们深入研究了实现的细节,我们需要问自己如何处理过期引用 。 有两种基本策略:

  1. 没有过时的引用,这意味着注册的对象自动注销自己在破坏。 该机构可以在一个基类被分解。

  2. 检查他们的时候,懒洋洋地收集陈旧的人有一种方法来分辨好和陈旧引用。 该机构可以采用强制执行shared_ptr / weak_ptr一对和意识到weak_ptr是的观察员 shared_ptr

这两种解决方案是可行的,并没有实现是完美的。 基类机制假定你其实可以修改你的类层次结构,而weak_ptr伎俩假设所有观察将堆分配和他们的一生被控制weak_ptr

我将使用做出了榜样shared_ptr (和使用了一些C ++ 11的设施,虽然没有强制这里):

class EventManager {
    typedef std::unique_ptr<Observer> OPtr;
    typedef std::vector<OPtr> Observers;
public:

    // Callback observers of "name"
    // Returns the number of observers so invoked
    size_t signal(std::string const& name) const {
        auto const it = _observers.find(name);
        if (it == _observers.end()) { return 0; }

        Observers& obs = it->second;

        size_t count = 0;
        auto invoker = [&count](OPtr const& p) -> bool {
            bool const invoked = p->invoke();
            count += invoked;
            return not invoked; // if not invoked, remove it!
        };

        obs.erase(std::remove_if(obs.begin(), obs.end(), invoker), obs.end());

        if (obs.empty()) { _observers.erase(it); }

        return count;
    }

    // Registers a function callback on event "name"
    void register(std::string const& name, void (*f)()) {
        _observers[name].push_back(OPtr(new ObserverFunc(f)));
    }

    // Registers an object callback on event "name"
    template <typename T>
    void register(std::string const& name, std::shared_ptr<T> const& p, void (T::*f)()) {
        _observers[name].push_back(OPtr(new ObserverMember<T>(p, f)));
    }


private:
    struct Observer { virtual ~Observer() {} virtual bool invoke() = 0; };

    struct ObserverFunc: Observer {
        ObserverFunc(void (*f)()): _f(f) {}

        virtual bool invoke() override { _f(); return true; }

        void (*_f)();
    };

    template <typename T>
    struct ObserverMember: Observer {
        ObserverT(std::weak_ptr<T> p, void (T::*f)()): _p(p), _f(f) {}

        virtual bool invoke() override {
            std::shared_ptr<T> p = _p.lock();
            if (not p) { return false; }

            p->*_f();
            return true;
        }

        std::weak_ptr<T> _p;
        void (T::*_f)();
    };

    // mutable because we remove observers lazily
    mutable std::unordered_map<std::string, Observers> _observers;
}; // class EventManager


Answer 2:

你将不得不使用std::function 。 这是实现一个通用的回调的唯一途径。 只要你涉及函数指针,而不是函数对象,它是不通用的,将永远是通用的,且永远不能做成通用的。

unordered_map<string, vector<std::function<void()>>>

函数指针是坏的,不应该在C ++中明确使用,只传递给像模板std::bindstd::function的构造,和成员函数指针是雪上加霜。



Answer 3:

您可以使用仿函数来实现这一目标。 如果您环绕你的成员函数算符可以使一个向量出函子。 仿函数如下:

template <class T> class MyFunctor
{
private:
    T* ObjectPtr;
    void (T::*MemberFunction) ();
public:
    void operator () ()
    {
        return (*this->ObjectPtr.*this->MemberFunction)();
    }
};

因此,基本上函子覆盖()运算并返回存储在函子类的成员函数。 如果你希望他们有不同的签名工作,但在这篇文章中,你可以得到进一步的信息可函子是相当复杂的。

http://www.codeproject.com/Articles/7112/Pointers-to-Member-Functions-and-Functors



Answer 4:

这是你应该使用多态,而不是函数(或成员函数)指针的典型案例。

正如你指出,你的组件类必须从通用类组件,其中包含虚拟方法(S)表示事件(一个或多个)继承:

class Component
{
public:
    virtual void OnPlayerLevelUp()
    {
    }
};

class ComponentSound : public Component
{
public:
     // override it
    void OnPlayerLevelUp()
    {
        // do the actual work
    }
};

你的ListEvent型现在这个样子:

typedef unordered_map<EventKey, vector<Component*>> ListEvent;

作为可选无效* paramenter事件的方法,你可以指定它作为可选参数,但事实证明这是一个void *是一个不好的征兆(用void *,可导致类型安全的损失),所以我会建议你找一个不同的方式来实现你想要什么。



文章来源: Store Function Pointers to any Member Function