为何基类指针指向派生类对象时调用A::h()而非B::h()?
问题解析:为什么A*指针调用h()时始终执行A::h()
先拆解核心问题的关键原因,结合C++的函数绑定规则与继承特性逐一说明:
1. 核心前提:A类的h()并非虚函数
你的代码里,A类只有f()和g()被声明为virtual,h(A*)没有virtual修饰。这意味着h()的调用是静态绑定——编译器在编译阶段就会根据指针的静态类型(也就是A*)确定要调用的函数,完全不考虑指针指向对象的实际类型(B)。
不管你传入的参数是&a_object(A*)还是&b_object(B可隐式转换为A),编译阶段就已经锁定了A::h(A*),运行时不会有动态分发的过程。
2. B类的h()是重载而非重写
就算A的h()是虚函数,B类中的h(B*)也不是对基类h()的重写:
- 重写要求函数签名完全一致(参数类型、数量、const属性等必须匹配),基类h的参数是
A*,子类是B*,属于重载而非重写。 - 子类的同名函数会隐藏基类的所有同名重载版本,但这个规则只在通过子类对象/指针调用时生效。你用的是
A*指针,编译器只能看到基类中声明的h(A*),自然只会调用这个版本。
验证修改:让B的h()正确重写A的版本
如果把A的h()改为虚函数,同时让B的h()签名和基类一致:
class A { public: virtual void f(int){cout << "A::f(int)" << endl;} virtual void g(double){cout << "A::g(double)" << endl;} virtual int h(A*){cout << "A::h()" << endl; } // 添加virtual }; class B: public A { public: void f(int){cout << "B::f(int)" << endl;} int h(A*) override {cout << "B::h()" << endl;} // 签名匹配,用override强制检查 };
此时用A*指针调用h(),才会触发动态绑定,执行B::h()。
总结
- 非虚函数调用是静态绑定,由指针的静态类型决定;
- 重写虚函数必须保证签名完全一致,否则只是重载;
- 子类同名函数隐藏基类版本,但仅在通过子类类型访问时生效。
内容的提问来源于stack exchange,提问作者Jasmeet Singh
相关产品推荐
相关产品推荐

