2

I'm having some troubles getting the design which I planned into C++ code.

I have a Manager class, which will create some instances of another class SomeClass. These instances will do some work in seperate threads. One of these instances will be designated as theOne and will notify the manager in some way when it is done performing its task. From that notification, the manager should get the results (if available) of all other instances with some function getData().

I thought I can realize this via a callback style notification. In the sense that the manager registers its getData() function in the instanciated class, which is the theOne, as a callback. If theOne has finished its job, it will just call its isDone() member, which executes the registered callback inside the manager. However doing it this way SomeClass always needs to have a reference to the Manager instance, which I actually don't want, because I only want the manager to know of SomeClass (instances) and not the other way around.

Is there a way I can tackle this problem? Or is my design just not suited for that? If it is not, is there another more suitable design with which I can realize this.

Here is the code I got (which is adapted from here). The calls I'm doing in main() will of course later be called in the respective class members.

#include <functional>
#include <iostream>

class Manager {
    public:
    void getData(int)
    {
        std::cout << "Got it!";
    }
};

class SomeClass {
public:
    SomeClass() : callback() { }
    typedef std::function<void(Manager*, int)> Callback;

    void registerCallback(const Callback& c)
    {
        callback = c;
    }

    void isDone(Manager* p)
    {
        callback(p, 42);
    }
private:
    Callback callback;
};

int main()
{
    // This should be called in the manager class, which will instanciate its
    // SomeClass workers. This works fine.
    SomeClass sc;
    sc.registerCallback(&Manager::getData);

    // This should be called in SomeClass. 
    // The manager object is needed for the execution of the callback, which I
    // want to omit.
    Manager cb;
    sc.isDone(&cb);
}
Community
  • 1
  • 1
lmNt
  • 3,822
  • 1
  • 16
  • 22

1 Answers1

1

You can make the callback generic, and pass a function object that captures a pointer to the Manager:

// in SomeClass
typedef std::function<void(int)> Callback;
Callback callback;

and instantiate as needed. For example, in manager:

// in Manager
using namespace std::placeholders;
auto f1 = std::bind(&Manager::getData, this, _1);
auto f2 = [this](int i) { getData(i); }
SomeClass sc;
sc.registerCallback(f1);
sc.registerCallback(f2);

or anywhere else:

void foo(int i) { std::cout << "foo called with i = " << i << "\n"; }

SomeClass sc;
sc.registerCallback(foo);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480