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::variantstd::visit等工具,可以实现更灵活且无虚函数的多态设计。
  • • 也有研究和实践表明,在静态链接程序中完全可以避免虚函数,使用模板和类型擦除技术达到相同目的。

总结

实现方式 多态时机 虚函数开销 灵活性 适用场景
虚函数多态 运行时 需要动态扩展接口
静态多态(CRTP) 编译时 性能敏感,类型固定
类型擦除 运行时 低(无虚表) 需要运行时多态但无虚函数开销
Tagged Union 运行时 类型有限,高性能需求

因此,完全可以实现具有多态行为但没有虚函数开销的类,关键在于根据需求选择合适的技术方案,如CRTP实现的静态多态、类型擦除技术或Tagged Union结构。
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)

阅读剩余
THE END