代码库的一个非常常见的模式是这样的 class Frobulator
{
public:
class Listener
{
private:
// only frobulators can frob
friend class Frobulator;
virtual void onFrobbed() = 0;
}
void maybeFrob()
{
// assume we always frob, but maybe we only do it sometimes
// and the caller won't know if a call will do it
for (auto& l: listeners)
{
l->onFrobbed();
}
}
void addListener(Listener* l)
{
listeners.push_back(l);
}
private:
std::vector<Listener*> listeners;
}
事件:
Listener
然后,一个类继承Frobulator
并且可以注册为Frobulator
的监听器。当某个来电者(不一定是听众)打电话后Frobulator
来说,听众会被告知。
我真正的问题是,如果听众在内部听#34;因此需要对private
进行非const引用,而是使用Listener
进行管理{ {1}}性质?
class FrobReactor: private Frobulator::Listener
{
public:
FrobReactor(Frobulator& frobulator_)
frobulator(frobulator)
{
frobulator.addListener(this);
}
private:
void onFrobbed() override
{
// react!
}
Frobulator& frobulator;
}
// and externally ...
Frobulator theFrobber;
FrobReactor reactor(theFrobber);
theFrobber.maybeFrob();
或者听众应该采用const-reference(如果你不需要也不参考),承认FrobReactor
没有修改Frobulator
但是宣传它是Frobulator::Listener
并期望客户端代码将其连接起来:
class FrobReactor: public Frobulator::Listener
{
public:
FrobReactor(const Frobulator& frobulator_):
frobulator(frobulator_)
{
}
private:
void onFrobbed() override
{
// react!
}
const Frobulator& frobulator;
}
// and externally
Frobulator theFrobber;
FrobReactor reactor(theFrobber);
theFrobber.addListener(&reactor);
theFrobber.maybeFrob();
或者,可以将addListener
方法设为const,并将侦听器列表mutable
设置为第一个方法也可以使用非const引用,但这感觉就像是一个黑客。
是否有&#34;权利&#34;这样做的方法?
答案 0 :(得分:1)
我不会在FrobReactor中存储对观察到的(或听过的)Frobulator的引用。相反,我会将对Frobulator实例的const引用传递给onFrobbed
方法。
class Listener
{
private:
// only frobulators can frob
friend class Frobulator;
virtual void onFrobbed(const Frobulator& frobulator) = 0;
}
并适应maybeFrob
:
void maybeFrob()
{
// assume we always frob, but maybe we only do it sometimes
// and the caller won't know if a call will do it
for (auto& l: listeners)
{
l->onFrobbed(*this);
}
}
至于addListener是否应该是const(因此,监听器的向量是否应该是可变的),这取决于你想要实现的目标。我同意它感觉很乱,但另一方面,如果你想确保你的API的客户只处理const Frobulators,那么这是一种方法。另一种方法是在API中的某个位置处理一个方法来处理向Frobulators添加监听器,如下所示:
void addListener(const Frobulator& frobulator, Frobulator::Listener& listener) {
Frobulator& nonConst = // obtain non-const reference to this frobulator
nonConst.addListener(listener);
}
这取决于你的设计。否则,如果您只想保护侦听器不要修改Frobulators,那么将const引用传递给&#39; onFrobbed方法似乎就足够了。
最后,我会像这样更改addListener
:
void addListener(Listener& listener)
{
listeners.push_back(&listener);
}
这是一个很小的改动,但我更倾向于在转移所有权时传递指针,除非有其他理由传递指针。当然,你必须确保你的听众在任何一种情况下都不会被删除(超出范围)。