C++怎么使用虚函数_C++多态机制教程【面向】

1次阅读

虚函数必须在基类中用virtual显式声明,否则不触发多态;多态仅通过指针或引用实现,对象传值或赋值会导致切片子类重写须加override防误定义,析构函数需virtual防内存泄漏。

C++怎么使用虚函数_C++多态机制教程【面向】

虚函数必须在基类中用 virtual 显式声明

不加 virtual,哪怕子类写了同名函数,调用时也不会走多态——编译器只看指针/引用的静态类型。这是最常踩的坑:以为“名字一样就自动多态”,结果 Base* p = new Derived(); p->func(); 调的还是 Base::func()

实操建议:

  • virtual 只需写在基类声明里,子类重写时加不加都行(c++11 起推荐加 override
  • 纯虚函数写成 virtual void func() = 0;,含纯虚函数的类就是抽象类,不能实例化
  • 析构函数如果可能通过基类指针删除派生对象,必须声明为 virtual,否则派生部分内存泄漏

运行时多态只对指针和引用生效

直接用对象变量调用,比如 Base b = derived_obj;(发生切片),再调 b.func(),永远绑定到 Base::func()。多态不是靠函数名,而是靠“间接访问”机制——只有通过指针或引用,才能触发虚函数表查找。

常见错误现象:

立即学习C++免费学习笔记(深入)”;

  • 把派生类对象赋值给基类对象(非指针/引用),以为能多态,实际发生对象切片,派生成员全丢
  • 函数参数传值(void f(Base b)),进来就切片,内部调 b.func() 不会多态
  • 正确做法是传 Base&Base*

overridefinal 是 C++11 后必备的安全补丁

没加 override 时,子类函数签名稍有偏差(比如参数 const 性不同、返回类型协变没满足),就会变成新函数而非重写,虚函数表里根本没它——运行时静默调错函数,极难排查。

实操建议:

  • 只要意图重写虚函数,就在子类声明后无条件加 override,编译器立刻报错提示签名不匹配
  • 确定某个虚函数不再被进一步重写,就在基类或中间类里用 final(如 virtual void f() final;),防止意外继承破坏契约
  • overridefinal 都是标识符,不是关键字,但只在虚函数重写上下文有效

虚函数调用有轻微开销,但别过早优化

每次调用要查虚函数表(vtable),多一次间接寻址,比普通函数调用慢一点。但在绝大多数业务逻辑里,这点开销远小于 IO、内存分配或算法复杂度本身。

需要注意的点:

  • 高频内层循环里反复调用虚函数(比如每帧上万次的图形渲染钩子),才值得考虑用模板或策略模式规避
  • 开启编译器优化(-O2)后,部分虚调用可能被 devirtualize(如编译期能确定唯一类型)
  • 真正影响性能的往往是虚函数背后做的事(比如锁、拷贝、动态分配),而不是虚调用本身

虚函数表布局、RTTI、多重继承下的虚函数行为,这些细节一旦涉及,问题会立刻从“语法是否写对”滑向“内存模型是否理解”。初学阶段盯住 virtualoverride、指针/引用这三点,已经能覆盖 95% 的多态使用场景。

text=ZqhQzanResources