I'm writing some code that includes events which are custom-implemented and class that uses these events and invokes them when something happens(ex. window closes). It looks something like this:
// phony.h
class Phony
{
public:
Phony();
~Phony();
// some stuff
void i_invoke_click();
void i_invoke_resize();
private:
Event<Arg1> click;
Event<> resize;
Event<Arg2> event3;
Event<Arg3> event4;
};
// event.h
template <typename... Args>
class Event
{
public:
void invoke(Args... params) const
void add(std::function<void(Args...)> func)
void remove(std::function<void(Args...)> func)
void operator =(std::function<void(Args...)> func) // same as add
void operator-=(std::function<void(Args...)> func) // same as remove
void operator()(Args... params) // invoke
private:
std::list<std::function<void(Args...)>> invoke_list;
};
Now I need to implement some interface so other classes could subscribe/unsubscribe to events like click. I have considered two ways to do this:
- Make access methods like
subscribe_to_click(func)
(which will make many methods and not convenient) - Or make events public so you could directly access them via =(which is convenient)
But I think that second way of putting events violates encapsulation but I'm not sure in it. So the question is: Is it okay to leave events public or I should make it the ugly(but safe) way?
CodePudding user response:
What I could suggest coming from a C# background is to use a base class like IObservable for the Events which implements some subscribe
method or your approach with operator overloading. Then make the IObservables public by returning a reference that refers to the events themselves:
#include <functional>
#include <list>
template <typename... Args>
class IObservable
{
public:
void operator =(std::function<void(Args...)> func); // same as add
void operator-=(std::function<void(Args...)> func); // same as remove
};
template <typename... Args>
class Event : public IObservable<Args...>
{
public:
void operator()(Args... params); // invoke
private:
std::list<std::function<void(Args...)>> invoke_list;
};
class Phony
{
public:
Phony();
~Phony();
void i_invoke_click();
void i_invoke_resize();
IObservable<int>& Click() { return click; }
IObservable<>& Resize() { return resize; }
IObservable<int>& Event3() { return event3; }
IObservable<int>& Event4() { return event4; }
private:
Event<int> click;
Event<> resize;
Event<int> event3;
Event<int> event4;
};
void foo(int x);
int main()
{
Phony p;
p.Click() = &foo;
// p.Click()(); no invoke possible
}