1.90、有没有实现具有多态行为但没有虚函数开销的类?
1. 多态与虚函数开销的关系
传统的运行时多态依赖虚函数和虚表(vtable),调用时需要间接跳转,带来性能开销和代码复杂度,同时阻碍编译器内联优化。
2. 静态多态(Static Polymorphism)
- • 通过**CRTP(Curiously Recurring Template Pattern)**实现。基类模板接受派生类作为模板参数,所有多态行为在编译期解析,消除虚函数调用开销。
- • 优点是性能极高,支持内联,缺点是类型必须在编译期确定,无法实现运行时动态切换。
- • 适合性能敏感且类型固定的场景。
示例简要:
template
struct Base {
void interface() {
static_cast(this)->implementation();
}
};
struct DerivedA : Base {
void implementation() { /* 实现A */ }
};
3. 类型擦除(Type Erasure)
- • 利用模板封装具体类型,隐藏真实类型,暴露统一接口,达到无虚函数的运行时多态效果。
- • 典型例子是
std::function
,也可自定义实现。 - • 相较虚函数,避免了虚表指针解引用,但仍有一定间接调用开销。
- • 适合需要运行时多态且想避免虚函数开销的场景。
4. Tagged Union(标记联合体)
- • 用枚举标记当前类型,联合体存储不同类型数据,使用
switch
分发调用对应函数。 - • 无虚函数开销,性能优于虚函数,但代码复杂度和扩展性较差。
- • 适合类型数量有限且性能要求高的场景。
5. 现代C++趋势
- • C++20及以后,利用概念(concepts)、
std::variant
、std::visit
等工具,可以实现更灵活且无虚函数的多态设计。 - • 也有研究和实践表明,在静态链接程序中完全可以避免虚函数,使用模板和类型擦除技术达到相同目的。
总结
实现方式 | 多态时机 | 虚函数开销 | 灵活性 | 适用场景 |
虚函数多态 | 运行时 | 有 | 高 | 需要动态扩展接口 |
静态多态(CRTP) | 编译时 | 无 | 低 | 性能敏感,类型固定 |
类型擦除 | 运行时 | 低(无虚表) | 高 | 需要运行时多态但无虚函数开销 |
Tagged Union | 运行时 | 无 | 中 | 类型有限,高性能需求 |
因此,完全可以实现具有多态行为但没有虚函数开销的类,关键在于根据需求选择合适的技术方案,如CRTP实现的静态多态、类型擦除技术或Tagged Union结构。
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1895
文章版权归作者所有,未经允许请勿转载。
THE END