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
相关产品推荐
相关产品推荐

