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

子类中继承对象的行为以及virtual关键字对其的影响

子类中继承对象的行为以及virtual关键字对其的影响

咱们先看你给出的这段代码,先修正个小语法错误——Rose继承的时候多写了个class,正确的代码应该是这样:

class Flower {
public:
    void whoAmI() { cout << name() << endl; }
    string name() { return "flower"; }
};

class Rose : public Flower {
public:
    string name() { return "rose"; }
};

int main() {
    Flower a;
    Rose b;
    a.whoAmI();
    b.whoAmI();
}

接下来咱们聊聊你疑惑的点:按照你对继承的理解,是不是觉得b.whoAmI()应该输出rose?但实际运行起来,它会和a.whoAmI()一样输出flower,这是为啥呢?

这就得说到非虚函数的调用规则了:whoAmI是个普通成员函数,它调用name的时候,是根据函数所在类的类型来决定调用哪个版本的。也就是说,whoAmI属于Flower类,不管是Flower对象还是Rose对象调用它,它都会默认调用Flower自己的name方法,根本不会去看子类有没有重写name。

那怎么让它“聪明”起来,知道调用子类重写的方法呢?这时候virtual关键字就派上用场了!

咱们把Flower里的name函数改成虚函数,代码调整成这样:

class Flower {
public:
    void whoAmI() { cout << name() << endl; }
    virtual string name() { return "flower"; } // 加virtual关键字
};

class Rose : public Flower {
public:
    string name() { return "rose"; } // 子类重写虚函数,这里可以加override更清晰,不过不加也能运行
};

这时候再运行,a.whoAmI()还是输出flower,但b.whoAmI()就会输出rose啦!

为啥会这样?因为当函数被声明为virtual后,C++会采用动态绑定的方式:它会根据调用这个函数的实际对象类型来决定用哪个版本的函数。b是Rose类型的对象,所以调用name的时候,就会找到Rose里重写的那个版本。

另外补充个小知识点:如果把whoAmI也声明成虚函数,效果是一样的吗?其实不一样,但在这个例子里结果相同。不过核心还是name作为虚函数,才能让子类的重写被正确调用。

总结一下:

  • 普通成员函数(非virtual)是静态绑定,看函数所属的类类型,不管实际对象是谁
  • 虚函数是动态绑定,看调用函数的实际对象类型,会优先用子类重写的版本

备注:内容来源于stack exchange,提问作者m112120

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:13:08