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

C++静态与动态决议:虚函数调用规则及相关代码技术问询

C++虚函数决议:对象调用vs指针/引用调用的核心区别

Hey there!咱们来好好拆解你提到的这个C++虚函数规则,结合你给出的代码片段把这个逻辑捋明白~

首先先明确你说的核心规则(这可是C++多态的关键知识点哦):

使用对象调用虚函数始终会进行静态决议,仅通过指针或引用调用时才会触发动态决议

先把这个规则的本质说透

C++的多态依赖动态绑定,但动态绑定不是随便触发的——只有当你通过指针或者引用调用虚函数时,才会在运行时去判断实际指向的对象类型,然后调用对应的函数。

而如果直接用对象(注意,不是指针/引用)调用虚函数,编译器在编译阶段就100%确定了这个对象的类型,毕竟对象本身的类型是固定死的,哪怕是子类对象赋值给基类对象发生切片,基类对象的类型还是基类,所以直接就做静态绑定,编译时就把函数调用给确定了。

结合你的代码片段来分析(我补全了常见的多态场景)

先把你给的代码补成完整的多态示例,方便咱们看效果:

#include <iostream>
class Mainclass{
protected:
    double length{1.0};
    double width{1.0};
    double height{1.0};
public:
    Mainclass(double lv, double wv, double hv):length{lv}, width{wv}, height{hv}{
        std::cout<<"Three args box ran"<<std::endl;
    }
    // 把showVolume设为虚函数,这是多态的前提
    virtual void showVolume() const{
        std::cout << "Mainclass Volume: " << length * width * height << std::endl;
    }
};

// 定义一个子类,重写showVolume
class Subclass : public Mainclass{
public:
    Subclass(double lv, double wv, double hv) : Mainclass(lv, wv, hv) {}
    void showVolume() const override{
        std::cout << "Subclass Volume: " << length * width * height * 2 << std::endl;
    }
};

情况1:直接用对象调用(静态决议)

看这段代码的运行结果:

int main(){
    Subclass sub(2, 3, 4);
    Mainclass mainObj(2, 3, 4);
    
    sub.showVolume(); // 编译时就确定调用Subclass的showVolume
    mainObj.showVolume(); // 编译时确定调用Mainclass的showVolume
    
    // 哪怕把子类对象赋值给基类对象(发生切片)
    Mainclass slicedObj = sub;
    slicedObj.showVolume(); // 还是调用Mainclass的showVolume!因为slicedObj是Mainclass类型的对象
}

这里的核心是:对象的类型是编译期就能确定的,编译器根本不需要等到运行时,直接把函数调用绑定到对应类的实现上。

情况2:用指针/引用调用(动态决议)

再看这段:

int main(){
    Subclass sub(2, 3, 4);
    Mainclass* ptr = &sub;
    Mainclass& ref = sub;
    
    ptr->showVolume(); // 运行时才确定调用Subclass的showVolume
    ref.showVolume(); // 同样是运行时动态绑定到Subclass的实现
}

这时候指针/引用的静态类型是Mainclass*/Mainclass&,但它们实际指向的是Subclass对象。编译器在编译期没法知道这个指针/引用最终指向的是什么类型的对象,所以会在运行时通过虚函数表(vtable)找到实际对象对应的函数实现,这就是动态决议。

最后再总结下为啥有这个区别

  • 对象本身是“完整”的实体,它的类型是固定的,编译器能直接确定要调用哪个函数。
  • 指针/引用只是一个“指向对象的工具”,它们的静态类型和实际指向对象的动态类型可能不一样,这时候就需要动态绑定来实现多态的效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:57:40