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

菱形继承问题

先来看程序......

#include <iostream>
using namespace std;

class Animal{   //动物
public:
	int m_Age;
};
class horse : public Animal{   // 马
};
class donkey : public Animal{    // 驴
};
class mule : public horse, public donkey{   // 骡子
};

void test()
{
	mule m;
	m.m_Age = 10;    // 这里提示  "mule::m_Age"不明确
}
int main()
{
	return 0;
}

上面程序的问题或许可以用作用域来区分一下,

#include <iostream>
using namespace std;

class Animal{   //动物
public:
	int m_Age;
};
class horse : public Animal{   // 马
};
class donkey : public Animal{    // 驴
};
class mule : public horse, public donkey{   // 骡子
};

void test()
{
	mule m;
	m.horse::m_Age = 10;
	m.donkey::m_Age = 12;

	cout << "m.horse::m_Age: " << m.horse::m_Age << endl;
	cout << "m.donkey::m_Age: " << m.donkey::m_Age << endl;
}
int main()
{
	test();
	return 0;
}

打印结果是

可以看到程序可以正常运行了,但是还有一个问题,就是骡子的年龄有了两个值(菱形继承导致存在两个数据),下来看一下底层

复制当前项目路径,然后打开  开发人员命令提示符(在开始菜单栏里)  输入命令:cl /d1 reportSingleClassLayoutmule "main.cpp"   报告单个类布局

从上图可以明显看到mule骡子类,继承到了连个数据,但一个骡子只能有一个年龄,因此利用虚继承解决菱形继承问题

#include <iostream>
using namespace std;

class Animal{   //动物  虚基类
public:
	int m_Age;
};
class horse : virtual public Animal{   // 马
};
class donkey : virtual public Animal{    // 驴
};
class mule : public horse, public donkey{   // 骡子
};

void test()
{
	mule m;
	m.horse::m_Age = 10;
	m.donkey::m_Age = 12;
        //此时就可以写成 m.m_Age = 15;  也不会有问题了

	cout << "m.horse::m_Age: " << m.horse::m_Age << endl;
	cout << "m.donkey::m_Age: " << m.donkey::m_Age << endl;
}
int main()
{
	test();
	return 0;
}

此时程序结果就是 12 了,对m.horse::m_Age 、m.donkey::m_Age 操作的就是一块内存了,再来看看mule类的底层实现

vbptr 虚基类指针,horse类的虚基类指针指向 $vbtable@horse@,其中存储了一个偏移量 8,那么 0+8 就找到了 虚基类的m_Age的地址。donkey类的也是一样。

相关文章:

  • 改善程序与设计的N个做法
  • C++数据结构之顺序表
  • C++数据结构之单链表
  • (8)STL算法之替换
  • (9)STL算法之逆转旋转
  • NFS安装使用
  • STL之map(关联式容器)
  • STL之unordered_map
  • 动态规划
  • 算法分析
  • 编写一个函数,实现将char类型的字符串,循环右移n个位置
  • 类构造、析构、赋值函数示例
  • 数组指针指针数组
  • LeeCode 20.有效的括号
  • LeeCode 26 删除排序数组中的重复项,返回数组新长度
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • Cookie 在前端中的实践
  • CSS实用技巧干货
  • css属性的继承、初识值、计算值、当前值、应用值
  • Javascript基础之Array数组API
  • k8s 面向应用开发者的基础命令
  • leetcode98. Validate Binary Search Tree
  • linux安装openssl、swoole等扩展的具体步骤
  • markdown编辑器简评
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • supervisor 永不挂掉的进程 安装以及使用
  • 大快搜索数据爬虫技术实例安装教学篇
  • 后端_ThinkPHP5
  • 记一次和乔布斯合作最难忘的经历
  • 解析 Webpack中import、require、按需加载的执行过程
  • 如何实现 font-size 的响应式
  • 项目实战-Api的解决方案
  • 06-01 点餐小程序前台界面搭建
  • Java性能优化之JVM GC(垃圾回收机制)
  • 阿里云ACE认证学习知识点梳理
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • (14)Hive调优——合并小文件
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)visual stdio 书签功能介绍
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .naturalWidth 和naturalHeight属性,
  • .NET Framework杂记
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET 依赖注入和配置系统
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042