考虑一个事件系统,其中具有以下类:
class Event_dispatcher {
private:
Listener_collection listeners;
public:
void add_listener(Listener _listener) { ... }
void remove_listener(Listener _listener) { ... }
void post_event(Event _event) { ... }
};
我打算在类中拥有Event_dispatcher
的实例,这些实例旨在发送事件。但是,我只希望从类内部发布事件,这样用户就只能添加或删除侦听器,而不能发布事件
简单的解决方案是使Event_dispatcher
成为封闭类的私有成员,但随后,我必须将add_listener
和remove_listener
定义为将参数转发给事件调度程序的公共成员
我知道这两种方法似乎不多,但请记住,这只是一个例子,我故意缩短了它。想象一下同样的问题,我必须以类似的方式定义大量的方法。
我想知道是否有一种常见或推荐的方法来解决这样的问题。我想到的一个解决方案是定义这样一个接口类:
class Event_dispatcher_interface {
private:
Event_dispatcher* event_dispatcher;
public:
void add_listener(Listener _listener) { event_dispatcher->add_listener(_listener); }
void remove_listener(Listener _listener) { event_dispatcher->remove_listener(_listener); }
};
并使其成为封闭类的公共成员。内部的指针(*event_dispatcher
(将指向封闭类的私有成员Event_dispatcher
,以便只允许从类内部发布事件。
如果还有其他(更好的(解决方案,我将不胜感激。
您可以使用继承来继承可见性
class Event_dispatcher {
private:
Listener_collection listeners;
public:
void add_listener(Listener _listener) { ... }
void remove_listener(Listener _listener) { ... }
protected:
void post_event(Event _event) { ... }
};
然后
struct MyClass : Event_dispatcher
{
// accessible as public
// void add_listener(Listener _listener);
// void remove_listener(Listener _listener);
// only usage from within the class
//void post_event(Event _event);
};
此方法依赖于委派和友谊。
您可以将所有Event_dispatcher
成员函数设置为私有函数,并将大友谊设置为访问这些成员函数的单独类:
class Event_dispatcher {
friend class Listener_manager;
friend class Event_poster;
// all private
void add_listener(Listener _listener) { /* */ }
void remove_listener(Listener _listener) { /* */ }
void post_event(Event _event) { /* */ }
Listener_collection listeners;
};
然后,定义分别提供对add_listener()
/remove_listener()
和post_event()
的访问的Listener_manager
和Event_poster
类。它们都依赖委派:
struct Listener_manager {
Listener_manager(Event_dispatcher& ed): dispatcher(ed) {}
void add_listener(Listener _listener) {
dispatcher.add_listener(_listener);
}
void remove_listener(Listener _listener) {
dispatcher.remove_listener(_listener);
}
private:
Event_dispatcher& dispatcher;
};
struct Event_poster {
Event_poster(Event_dispatcher& ed): dispatcher(ed) {}
void post_event(Event _event) { dispatcher.post_event(_event); }
private:
Event_dispatcher& dispatcher;
};
在类中,将这些类的对象声明为数据成员。您可以单独控制每个成员的访问权限:
struct MyClass {
public:
MyClass(): listener(dispatcher), poster(dispatcher) {}
private:
Event_dispatcher dispatcher;
public: // accessible from the outside
Listener_manager listener_manager; // add_listener()/remove_listener()
private:
Event_poster event_poster; // post_event()
};
您可以将add_listener()
和remove_listener()
称为:
MyClass obj;
obj.listener.add_listener(listener);
obj.listener.remove_listener(listener);
由于成员event_poster
是私有的,因此其成员函数post_event()
只能在MyClass
内部访问。
使用CRTP
相反,您可以保留Event_dispatcher
类成员的原始可访问性,并定义以下类模板Accessor<>
,它将处理委派部分:
template<typename T>
class Accessor {
public:
void add_listener(Listener _listener) {
static_cast<T&>(*this).event_dispatcher.add_listener(_listener);
}
void remove_listener(Listener _listener) {
static_cast<T&>(*this).event_dispatcher.remove_listener(_listener);
}
};
然后,从这个在定义类本身上实例化的类模板公开继承(即CRTP(:
struct MyClass: Accessor<MyClass> {
friend class Accessor<MyClass>;
private:
Event_dispatcher event_dispatcher;
};
您仍然需要将友谊授予基类,以便它可以访问私有数据成员event_dispatcher
,并且该成员必须具有此名称。
通过这种方式,您可以以更简洁的方式访问Event_dispatcher::add_listener()
和Event_dispatcher::remove_listener()
:
MyClass obj;
obj.add_listener(listener);
obj.remove_listener(listener);
我相信您正在寻找的是朋友类:
cplusplus.com在这个上有一个很好的页面
TLDR
当您将类B指定为类a的朋友时,类B可以完全访问类a的私有功能。
试试这个:
class Outer_Class {
public:
Event_dispatcher my_event_dispatcher;
// whatever else is public
private:
void example_func();
};
class Event_dispatcher {
friend class Outer_Class;
private:
Listener_collection listeners;
void post_event(Event _event) { ... }
public:
void add_listener(Listener _listener) { ... }
void remove_listener(Listener _listener) { ... }
};
void Outer_Class::example_func(){
// In here, you can use the functions from the class that made it a friend
my_event_dispatcher.post_event(my_event);
}