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

为何基类指针指向派生类对象时调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:13:20