【问题标题】:c++ - access pointer to call method (using callbacks etc)c++ - 访问调用方法的指针(使用回调等)
【发布时间】:2022-01-14 15:13:22
【问题描述】:

我正在尝试弄清楚如何做到这一点。 我有 2 节课 -

class Caller(){
//constructs Callee

    void onEventFired(){
        //need to call a function on an obj
        //which I dont have access to here

        //objptr->funcA
    }
};

class Callee(){
//it has access to an instance of caller object
private:
    void setup(){
        std::unique_ptr objptr = make_unique<SampleClass>....
        //create unique ptr of obj

        //can pass the objptr to Caller through a
        //separate function but probably not clean ??
    }
};

事件链 - 调用者在自己的构造过程中创建被调用者实例,然后调用被调用者的设置函数,该函数创建 SampleClass 指针。稍后,当我想从 Caller 中调用 SampleClass 的 funcA 时,周期性事件开始触发

一种方法是通过单独的函数将原始 SampleClass 指针传递给 Caller 类,但理想情况下,我不希望 Caller 类可以访问它。 有没有办法使用一些回调,我可以干净地做到这一点。

【问题讨论】:

  • 通常被调用者将实现调用者定义的接口。例如,class Callee: public Caller::callback_client { ... }; 或在别处定义且对两者都可见的接口。
  • 这是我上面描述的一个例子:How to implement callbacks with interface
  • 现在我将使用std::function 和一个捕获被调用者实例的 lambda 表达式来创建一个简单的接口。
  • @code4fun 哦...好吧,从一开始就有这样的细节会很好... :-)
  • 这不灵活,这意味着您必须在每次添加新的被调用者时更改调用者代码。通过注册,您的被调用者可以在完全不同的库中,并且仍然能够获得回调。

标签: c++ pointers callback smart-pointers unique-ptr


【解决方案1】:

你的问题的动机有点弱,所以让我们稍微加强一下。

假设Caller 接受注册,希望在EVENT_FIRED 发生时被回调。所以,系统有这样的东西:

    //... initialize all callees
    //... wait for event
    switch (event) {
    //...
    case EVENT_FIRED:
        //...
        //callback all interested callees
        Caller::instance().onEventFired();
        break;
    //...
    default:
        //...
        break;
    };

通常,您会希望被调用者向Caller 实例注册自己,以便他们通过注册的回调获得事件通知。

为了接受注册,您可以在调用者中使用某种容器来跟踪它们。

class Caller {
public:
    struct Callback {
        virtual ~Callback () = default;
        virtual void fire () = 0;
    };

    static Caller & instance () {
        static Caller one;
        return one;
    }

    template <typename CALLBACK, int EVENT>
    void subscribe () {
        std::unique_ptr<Callback> cb(std::make_unique<CALLBACK>());
        callbacks_[EVENT].push_back(std::move(cb));
    }

    //...
    void onEventFired () {
        for (auto &cb : callbacks_[EVENT_FIRED]) cb->fire();
    }

private:
    typedef std::list<std::unique_ptr<Callback>> CallbackList;

    std::unordered_map<int, CallbackList> callbacks_;

    Caller () = default;
    Caller (const Caller &) = delete;
    Caller & operator = (Caller) = delete;
    ~Caller () = default;
};

Caller 现在实现了Callback 接口,并在安装过程中进行注册。

class Callee : public Caller::Callback {
public:
    static void setup () {
        Caller::instance().subscribe<Callee, EVENT_FIRED>();
    }
    void fire () { std::cout << "You're fired!\n"; }
};

Try it online!

【讨论】:

    【解决方案2】:

    这里有 2 个参考可能是您正在寻找的。 The Attorney-Client idiompass-key pattern

    Attorney-Client 惯用语是一种添加代理类的方法。 代理类是需要访问的类的朋友。 [Callee] - [Proxy] - [Caller] 关系已建立。

    Pass-Key 模式是解决问题的一种相对简单的方法。 使用friend关键字的主要思想是相同的。 但是,它使用的是类模板,植根于模板元编程。 如需更复杂的用法,请查看this version。 (最后一个答案)

    【讨论】:

      猜你喜欢
      • 2012-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-18
      • 2021-10-07
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      相关资源
      最近更新 更多