You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++虚函数默认参数行为疑问:基类指针调用派生类函数参数异常

C++虚函数默认参数的行为解析

你遇到的这个现象是C++标准明确规定的行为,核心原因是虚函数的函数体调用是动态绑定,但默认参数是静态绑定,两者的绑定时机完全不同:

  • 动态绑定(函数体选择):虚函数的调用逻辑在运行时确定,编译器会根据指针指向对象的实际类型选择对应的函数体。当A* pa = new B;时,pa的静态类型是A*,但实际指向的是B类型对象,因此运行时会调用B::f()的函数体,这就是输出中出现"In B::f(30)"的原因。
  • 静态绑定(默认参数选择):默认参数的值在编译阶段就已确定,编译器只会根据指针的静态类型(即声明时的类型)选择默认参数。这里pa的静态类型是A*,所以编译器会使用A::f()中定义的默认参数20,而非B::f()的30。

结合代码执行过程来看:当执行pa->f();时,编译阶段编译器已经把默认参数替换为20;运行阶段,虚函数机制触发,实际执行B::f()的逻辑,用20代入n-4计算,最终得到结果16,也就出现了你看到的输出:In B::f(30) with n = 20 and n-4 = 16。

这种设计是为了兼顾效率与多态特性——默认参数在编译期确定可以避免运行时额外开销,而虚函数的动态绑定则实现了运行时多态。需要注意的是,在派生类中重写虚函数时,建议保持默认参数与基类一致,避免出现这种易混淆的行为。

示例代码

#include <iostream>  
// C++98
using std::cout; using std::endl;

class A {
    public: virtual void f(int n=20) { 
        cout << "In A::f(20) with n = " << n << " and n+2 = ";
        cout << n+2; 
    }
    virtual ~A() {}
};

class B : public A {
    public: virtual void f(int n=30) {
        cout << "In B::f(30) with n = " << n << " and n-4 = ";
        cout << n-4;
    }
};


int main () 
{
    A* pa1 = new A;
    pa1->f(); cout << endl;  // outputs 22, expected, 20+2
    B* pb = new B;
    pb->f(); cout << endl;  // outputs 26, expected, 30-4
   
    A* pa = new B;
    pa->f(); cout << endl; // outputs 16 , 20-4 , NOT expected by me! 
    delete pa1; delete pb; delete pa;
}

代码输出

In A::f(20) with n = 20 and n+2 = 22
In B::f(30) with n = 30 and n-4 = 26
In B::f(30) with n = 20 and n-4 = 16

内容的提问来源于stack exchange,提问作者GeorgiosDoumas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:12:23