带默认参数的C++虚函数调用行为变更问题咨询
问题分析:VS2013编译后虚函数调用异常的原因
核心问题:函数签名不匹配导致的非覆盖行为
你的代码中,DerivedItem的SetValue(int)并没有覆盖基类BaseItem的SetValue(int, int*)——两者的参数列表完全不同,这属于C++中的函数隐藏(name hiding),而非标准的虚函数覆盖。
VS编译器的行为变更
- 旧版本VC编译器存在非标准的宽松处理:当通过基类指针调用带默认参数的虚函数时,可能会忽略参数数量的差异,“匹配”到派生类参数更少的同名函数,这是不符合C标准的行为。
- VS2013严格遵循了C++标准:当调用
item->SetValue(5, nullptr)时,编译器会基于基类的函数签名(int, int*)查找对应的虚函数。由于派生类没有签名完全一致的覆盖版本,因此最终会调用基类的SetValue实现。
为什么修改派生类函数签名后恢复正常?
当你把DerivedItem的SetValue修改为和基类完全一致的签名(包括参数类型、数量,以及默认参数)后,派生类的函数才真正覆盖了基类的虚函数。此时通过基类指针调用时,C++的多态机制会正常触发,调用派生类的实现。
额外提示:此类写法的不良实践
- 永远不要在派生类中定义参数列表不同的同名虚函数,这会破坏多态逻辑,引发难以排查的调用异常。
- 虚函数的覆盖要求参数列表完全一致,默认参数不属于函数签名的一部分,但为了避免混淆,建议基类和派生类的默认参数保持一致。
内容的提问来源于stack exchange,提问作者Andrew KeepCoding
相关产品推荐
相关产品推荐

