没有虚拟调度的默认方法实现
Default method implementation without virtual dispatch
好的,所以我想我也想吃我的蛋糕。我认为这是不可能的,但我们开始了。
我正在研究一个简单的事件系统,其中回调是在某些用户定义的侦听器类中定义的,事件发射器将该类作为模板参数。采用模板参数的原因是我想避免使用虚拟调度调用侦听器方法。
// Class in charge of emitting events.
template<typename TListener = DefaultEmptyListener>
class Emitter {
public:
Emitter(TListener& l) : mListen(l) {}
EmitFoo(...) {
mListen.OnFoo(...);
}
EmitBar(...) {
mListen.OnBar(...);
}
private:
TListener& mListen;
};
class SomeUserDefinedListener() {
void OnFoo() {} // Not virtual
// OnBar(); --> Not defined. Want default implementation.
}
我的问题是我想避免让用户必须为所有可能的事件定义"On*"方法。也就是说,如果用户未提供方法,我希望侦听器类具有事件方法的默认实现。
有没有办法在不引入虚拟调度的情况下为侦听器提供默认实现?
当你处理在编译时已知确切类型的对象(即没有动态调度(时,你不需要virtual
。 只需创建一个基类,其中包含所有处理程序方法的默认实现,以及一个重写要自定义的处理程序的派生类,并将派生类作为模板参数传递。
如果您希望能够将基类作为TListener
模板参数传递,但随后mListen
变量实际上引用派生类的实例,则需要将处理程序函数声明为 virtual
。 但是,如果TListener
始终是mListen
引用的对象的确切类型,则不需要virtual
。
(顺便说一句,"虚拟继承"与普通的虚函数不同,我认为这就是你所指的。
您可以使用没有虚拟多态性的继承:
// Class in charge of emitting events.
template<typename TListener = DefaultEmptyListener>
class Emitter {
public:
Emitter(TListener& l) : mListen(l) {}
EmitFoo(...) {
mListen.OnFoo(...);
}
EmitBar(...) {
mListen.OnBar(...);
}
private:
TListener& mListen;
};
class SomeUserDefinedListener() : public DefaultEmptyListener {
void OnFoo() {} // Not virtual
// OnBar(); --> Not defined. DefaultEmptyListener implementation.
}
您可以在
C++17 中利用if constexpr
和检测习惯用语(其中ns::is_detected
std::experimental::is_detected
或类似(轻松做到这一点
// Class in charge of emitting events.
template<typename TListener = DefaultEmptyListener>
class Emitter {
public:
Emitter(TListener& l) : mListen(l) {}
EmitFoo(...) {
if constexpr (ns::is_detected_v<decltype(mListen.OnFoo(...)>>)
{ mListen.OnFoo(...); }
else
{ /* Default empty behaviour */ }
}
EmitBar(...) {
if constexpr (ns::is_detected_v<decltype(mListen.OnBar(...)>>)
{ mListen.OnBar(...); }
else
{ /* Default empty behaviour */ }
}
private:
TListener& mListen;
};
这可以使用正常的SFINAE方法向后移植到C++14/C++11。
相关文章:
- 初始化具有非默认构造函数的std::数组项的更好方法
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 在C++中使用默认构造函数初始化对象的不同方法
- 使用默认构造函数初始化对象的不同方法
- 使用 c++ 的 http 客户端的默认方法
- 有没有一种简单的方法来调用带有默认参数的函数?
- 将私有数据成员作为默认参数传递给该类的公共方法时出错
- C++ 实例化新对象时不接受继承方法默认参数值
- 有没有更优雅的方法在构造函数中声明默认变量?
- 模板类专业化具有成员变量和方法的默认值
- 有没有一种很好的方法来实现具有默认失败情况的条件类型?
- 是否有一种方法可以在超载运算符函数中接触默认运算符函数
- 如何从类构造函数传递值C++作为此类方法的默认参数?
- 如何从 pjsip 发送电子邮件.是否有任何可用于发送电子邮件的默认方法
- 从指针访问值或获取其默认值(如果为 null)的最干净方法
- 存储具有许多变体的类的默认值的推荐方法是什么?
- 没有虚拟调度的默认方法实现
- 什么是默认方法以及如何正确使用它们
- C++:为默认方法参数调用另一个方法
- 在c++中显式声明默认方法