当前位置: 首页 > article >正文

C++中的菱形继承问题

假设有一个问题,类似于鸭子这样的动物有很多种,如企鹅和鱿鱼,它们也可能会有一些共同的特性。例如,我们可以有一个叫做 AquaticBird (涉禽,水鸟的一类)的类,它又继承自 Animal 和 SwimmingAnimal,就像这样:

class AquaticBird : public Animal, public SwimmingAnimal {  // AquaticBird类既是Animal也是SwimmingAnimal  
};  

如果我们同时继承了这两个类,像下图所示,将发生菱形继承:

        Animal  /      \
FlyingAnimal   AquaticBird  \      /  Duck  

在这个结构中,Duck 既继承了 FlyingAnimal,也间接继承了 Animal 通过 AquaticBird 的方式。问题在于,如果我们试图调用 Animal 类的方法,例如 eat(),Duck 会造成二义性:它不清楚是通过哪个路径来调用 Animal 类的实例。

那么如何解决菱形继承问题呢

解决菱形继承问题

通过使用 虚继承,我们可以确保在最终的 Duck 类中,只有一个 Animal 的实例。


class Animal {  
public:  void eat() {  std::cout << "Eating food." << std::endl;  }  
};  
class FlyingAnimal : virtual public Animal { // 使用virtual  
public:  void fly() {  std::cout << "Flying." << std::endl;  }  
};  
class SwimmingAnimal : virtual public Animal { // 使用virtual  
public:  void swim() {  std::cout << "Swimming." << std::endl;  }  
};  
class Duck : public FlyingAnimal, public SwimmingAnimal {  // Duck类继承自FlyingAnimal和SwimmingAnimal  
};  

现在,当 Duck 类调用 eat() 方法时,编译器知道只有一份 Animal 的实例,从而避免了二义性。

那么虚继承的底层实现原理是什么呢?

g++ -fdump -class-hlerarchy *.cpp gcc8.0之前

g++ fdump -lang - class *.cpp gcc8.0及以后

通过虚表指针偏移来实现虚继承

父类的vptr都有到共同基类的偏移量,从而让子类多继承是指向同一个“父类的父类”

只有C++有菱形继承

一般不使用菱形继承,但在库里面使用了

如下所示,下面的箭头都是继承,我们就会发现中间出现了菱形继承,iostream继承了istream和ostream。

http://www.lryc.cn/news/2384080.html

相关文章:

  • 订单越来越到导致接口列表查询数据缓慢解决思路
  • word格式相关问题
  • 网络-MOXA设备基本操作
  • 飞桨paddle import fluid报错【已解决】
  • 测试工程师要如何开展单元测试
  • IPv4 地址嵌入 IPv6 的前缀转换方式详解
  • 野火鲁班猫(arrch64架构debian)从零实现用MobileFaceNet算法进行实时人脸识别(三)用yolov5-face算法实现人脸检测
  • IS-IS 中间系统到中间系统
  • 【图像生成大模型】HunyuanVideo:大规模视频生成模型的系统性框架
  • GitHub 趋势日报 (2025年05月19日)
  • 如何使用Java生成pdf报告
  • HarmonyOS鸿蒙应用规格开发指南
  • 【Harmony】【鸿蒙】List列表View如何刷新内部的自定义View的某一个控件
  • iisARR负均衡
  • uniapp打包报错:重新在manifest.json中生成自己的APPID
  • 人脸识别备案开启安全防护模式!紧跟《办法》!
  • 【爬虫】DrissionPage-7
  • 新浪《经济新闻》丨珈和科技联合蒲江政府打造“数字茶园+智能工厂+文旅综合体“创新模式
  • git 撤销最近的几次push
  • 水滴前端面经及参考答案
  • React 第四十五节 Router 中 useHref() Hook的使用详解及注意事项
  • 50、js 中var { ipcRenderer } = require(‘electron‘);是什么意思?
  • LeetCode 438. 找到字符串中所有字母异位词 | 滑动窗口与字符计数数组解法
  • @RequestParam 和 @RequestBody、HttpServletrequest 与HttpServletResponse
  • 计算机底层的多级缓存以及缓存带来的数据覆盖问题
  • SpringBoot-1-入门概念介绍和第一个Spring Boot项目
  • 服务器多用户共享Conda环境操作指南——Ubuntu24.02
  • 基于FPGA的电子万年历系统开发,包含各模块testbench
  • Leetcode刷题 | Day63_图论08_拓扑排序
  • MySQL 可观测性最佳实践