1.85、虚函数可以有默认参数吗?

虚函数可以有默认参数,但默认参数是静态绑定的,虚函数调用是动态绑定的,这导致默认参数的值由调用时指针或引用的静态类型决定,而非对象的动态类型。


关键点解析

  • • 默认参数绑定时机:默认参数在编译阶段绑定,编译器根据调用表达式的静态类型决定使用哪个默认值。
  • • 虚函数调用时机:虚函数的实际调用是在运行时,根据对象的动态类型决定调用哪个函数实现。
  • • 结果表现:即使调用了派生类重写的虚函数,传入的默认参数仍然是基类中声明的默认值,可能导致参数与函数实现不匹配,产生混淆和潜在错误。

典型示例

class Base {
public:
    virtual void fun(int x = 111) {
        std::cout fun();  // 输出 Derived::fun(), x = 111
    d.fun();    // 输出 Derived::fun(), x = 222
}

解释:

  • • bp->fun()调用的是Derived::fun(动态绑定),但默认参数xBase的声明决定(静态绑定为111)。
  • • d.fun()调用Derived::fun且默认参数由Derived声明决定(222)。

面试考察重点

  • • 理解虚函数的动态绑定与默认参数的静态绑定机制的区别
  • • 认识到虚函数默认参数可能导致调用时参数值与实际函数实现不匹配的风险。
  • • 掌握避免在虚函数中重新定义默认参数的最佳实践,通常建议只在基类声明默认参数,派生类不再重复定义默认参数。
  • • 理解更安全的设计方式是将默认参数放在非虚函数中,虚函数只负责具体实现,例如通过NVI(非虚接口)模式实现。

总结

  • • 虚函数可以有默认参数,但默认参数是静态绑定的,调用时以指针或引用的静态类型为准。
  • • 这会导致调用派生类虚函数时,默认参数仍然是基类的默认值,可能引发逻辑错误。
  • • 最佳实践是不在派生类中重新定义默认参数,或者避免在虚函数中使用默认参数,通过其他设计模式解决。
    本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
    (加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
THE END