C++编程——继承

2023-10-27


继承的知识点结构
在这里插入图片描述
继承是面向对象三大特性之一,例如动物类下可以有猫类、狗类。显然猫类、狗类都具有动物类的属性,于此同时,也就有自己独特的属性。这个时候,猫类、狗类就是继承于动物类, 采用继承的技术,可以减少重复的代码

1. 继承的基本语法

语法class 子类:继承方式 基类
继承示例
一般网页都有很多部分相似的,我们可以将这些相似的部分抽象出来,作为一个基类。然后子类只需要继承基类,在基类的基础上添加自身其他的属性或者方法就可以实现基本的功能,同时减少了重复代码。

//继承实现页面
//公共页面类
class BasePage
{
public:
	void header()
	{
		cout << "网页公共头部信息" << endl;
	}
	void footer()
	{
		cout << "网页公共底部信息" << endl;
	}
	void left()
	{
		cout << "网页公共分类列表信息" << endl;
	}
};


//Java页面
class Java :public BasePage
{
public:
	void content()
	{
		cout << "Java网页信息" << endl;
	}
};


//Python页面
class Python :public BasePage
{
public:
	void content()
	{
		cout << "Python网页信息" << endl;
	}
};


//CPP页面
class CPP :public BasePage
{
public:
	void content()
	{
		cout << "CPP网页信息" << endl;
	}
};

void test01()
{
	cout << "Java页面如下" << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();

	cout << "Python页面如下" << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();

	cout << "CPP页面如下" << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();
}


int main()	
{
	test01();
	system("pause");
	return 0;
}

2. 继承方式

继承方式一共有三种:

  • 公共继承public
  • 保护继承protected
  • 私有继承private

:保护访问权限和私有访问权限都是类内可访问,类外不能访问。但是两者的不同点会在继承中体现。

下面将说明发生继承后,子类访问权限的变化情况:
基类

class A
{
public:
	int a;
protected:
	int b;
private:
	int c;
};
  • 公有方式继承基类
class B :public A
{
public:
	int a;
protected:
	int b;
不可访问:
	int c:
};
  • 保护方式继承基类
class B :protected A
{
protected:
	int a;
	int b;
不可访问:
	int c:
};
  • 私有方式继承基类
class B :private A
{
private:
	int a;
	int b;
不可访问:
	int c:
};

3. 继承的对象模型

问题:从父类继承过来的成员,哪些是属于子类对象的?

先来看一段代码:

class Base
{
public: 
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

class Son : public Base
{
public:
	int m_D;
};

void test01()
{
	cout << "size of Son = " << sizeof(Son) << endl;
}


int main()	
{
	test01();
	system("pause");
	return 0;
}

输出的结果如下:
在这里插入图片描述
可以得到以下结论:

  1. 父类中所有非静态成员属性都会被子类继承下去
  2. 父类中私有成员属性是被编译器给隐藏了,因此访问不到,但是确实是被继承下去了

利用开发工具验证继承的对象模型

  1. 打开Visual Studio的开发人员命令提示符
    在这里插入图片描述
    2.将路径定位到所要查看类对象模型所在文件夹的路径
    在这里插入图片描述
    3.输入代码:cl(l代表字母l) /d1(1代表数字1) reportSingleClassLayout类名 类所在的文件名,并得到结果
    在这里插入图片描述

4. 继承中构造和析构顺序

示例

//继承中的构造和析构顺序
class Base
{
public:
	Base()
	{
		cout << "Base构造函数的调用" << endl;
	}

	~Base()
	{
		cout << "Base析构函数的调用" << endl;
	}
};


class Son :public Base
{
public:
	Son()
	{
		cout << "Son构造函数的调用" << endl;
	}

	~Son()
	{
		cout << "Son析构函数的调用" << endl;
	}
};


void test01()
{
	Son son;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述继承中的构造和析构顺序如下
先构造父类,再构造子类,析构的顺序与构造的顺序相反

5. 继承中同名成员处理

问题:当子类与父类出现同名成员,如何通过子类对象访问到子类或者父类中同名的数据呢?

  • 访问子类同名成员,直接访问即可
  • 访问父类同名成员,需要加作用域

示例

class Base
{
public:
	Base()
	{
		m_A = 100;
	}

	int m_A;
};


class Son :public Base
{
public:
	Son()
	{
		m_A = 200;
	}

	int m_A;
};


void test01()
{
	Son son;
	cout << "子类中的m_A = " << son.m_A << endl;
	cout << "父类中的m_A = " << son.Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
:同名成员函数的处理和同名成员属性的处理相同,要注意的是:如果子类中出现和父类同名的成员函数,子类的同名成员函数会隐藏掉父类中所有同名成员函数

6. 继承中同名静态成员处理方式

问题:继承中同名的静态成员在子类对象上如何进行访问?

静态成员和非静态成员出现同名时,处理方式一致

6.1 通过对象访问

class Base
{
public:
	static int m_A;
};
int Base::m_A = 100;


class Son :public Base
{
public:
	static int m_A;
};
int Son::m_A = 200;


void test01()
{
	Son s;
	cout << "子类中的静态成员m_A = " << s.m_A << endl;
	cout << "父类中的静态成员m_A = " << s.Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

6.2 通过类名访问

class Base
{
public:
	static int m_A;
};
int Base::m_A = 100;


class Son :public Base
{
public:
	static int m_A;
};
int Son::m_A = 200;


void test01()
{
	
	cout << "子类中的静态成员m_A = " << Son::m_A << endl;
	cout << "父类中的静态成员m_A = " << Son::Base::m_A << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

7. 多继承语法

C++允许一个类继承多个类
语法:class 子类: 继承方式 父类1, 继承方式 父类2 ...
:多继承可能会引发父类中有同名成员出现,需要加作用域区分,C++的实际开发中不建议用多继承的技术

7.1 多继承的对象模型

class Base1
{
public:
	Base1()
	{
		m_A = 100;
	}
	int m_A;
};



class Base2
{
public:
	Base2()
	{
		m_A = 200;
	}
	int m_A = 200;
};

class Son :public Base1,public Base2
{
public:
	Son()
	{
		m_C = 300;
		m_D = 400;
	}
	int m_C;
	int m_D;
};



void test01()
{
	Son s;
	cout << "sizeof Son = " << sizeof(s) << endl;
	cout << "Base1中的m_A = " << s.Base1::m_A << endl;
	cout << "Base2中的m_A = " << s.Base2::m_A << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

也可以利用开发者工具查看模型:
在这里插入图片描述

8. 菱形继承(钻石继承)

概念:两个派生类继承同一个基类,又有某个类同时继承着两个派生类

典型的菱形继承案例
动物作为基类,羊类和驼类作为动物的派生类,羊驼类同时继承羊类和驼类

菱形继承问题

  1. 羊继承了动物的数据,驼也同样继承了动物的数据,当羊驼使用数据时,就会产生二义性。
//动物类
class Animal
{
public:
	int m_Age;
};

//羊类
class Sheep: public Animal
{

};

//驼类
class Camel : public Animal
{

};

//羊驼类
class SheepCamel: public Sheep, public Camel
{
	
};


void test01()
{
	SheepCamel sc;
	sc.m_Age = 18; //这行代码就会报错,因此羊驼类继承了两份m_Age,直接调用sc.m_Age产生了二义性
	sc.Sheep::m_Age = 18;
	sc.Camel::m_Age = 20; //可以利用添加作用域的方式来解决二义性的问题
}


int main()
{
	test01();
	system("pause");
	return 0;
}
  1. 羊驼类实际上继承两份动物的数据,造成了内存的浪费(例如羊有年龄,驼也有年龄,羊驼都继承了羊类和驼类关于年龄的数据,但实际上羊驼的年龄只有一个,没有必要拥有两份关于年龄的数据)

可以参考多继承的对象模型:
在这里插入图片描述

采用虚基类解决菱形继承的问题
继承之前,加上关键字virtual变为虚继承

//动物类
class Animal
{
public:
	int m_Age;
};

//羊类
class Sheep:virtual public Animal
{

};

//驼类
class Camel :virtual public Animal
{

};

//羊驼类
class SheepCamel: public Sheep, public Camel
{
	
};


void test01()
{
	SheepCamel sc;
	sc.Sheep::m_Age = 18;
	sc.Camel::m_Age = 28;
	 
	cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl;
	cout << "sc.Camel::m_Age = " << sc.Camel::m_Age << endl;
	cout << "sc.m_Age = " << sc.m_Age << endl;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

说明:采用虚继承之后,菱形继承中羊驼类就只有一份年龄的数据了,解决了内存浪费的问题

虚继承的底层原理
我们利用开发者工具调出羊驼类的对象模型:
在这里插入图片描述
和未采用虚继承技术的对象模型相比,年龄的数据变成只有一份了,但是多了vbptr
vbptr称为虚基类指针,指针指向的是vbtable,也就是虚基类表,虚基类表中的内容其实就是一个偏移量

  • Sheep中的虚基类指针指向的虚基类表中的偏移量为8,(0+8=8)就找到了年龄数据的地址
  • Camel中的虚基类指针指向的虚基类表中的偏移量为4,(4+4=8)就找到了年龄数据的地址
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++编程——继承 的相关文章

  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • 如何使 Windows 窗体的关闭按钮不关闭窗体但使其不可见?

    该表单有一个 NotifyIcon 对象 当用户单击 关闭 按钮时 我希望表单不关闭而是变得不可见 然后 如果用户想再次查看该表单 可以双击系统托盘中的图标 如果用户想关闭表单 可以右键单击该图标并选择 关闭 有人可以告诉我如何使关闭按钮不
  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 使用 System.Text.Json 即时格式化 JSON 流

    我有一个未缩进的 Json 字符串 例如 hash 123 id 456 我想缩进字符串并将其序列化为 JSON 文件 天真地 我可以使用缩进字符串Newtonsoft如下 using Newtonsoft Json Linq JToken
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 如何使用 std::string 将所有出现的一个字符替换为两个字符?

    有没有一种简单的方法来替换所有出现的 in a std string with 转义 a 中的所有斜杠std string 完成此操作的最简单方法可能是boost字符串算法库 http www boost org doc libs 1 46
  • 防止索引超出范围错误

    我想编写对某些条件的检查 而不必使用 try catch 并且我想避免出现 Index Out of Range 错误的可能性 if array Element 0 Object Length gt 0 array Element 1 Ob

随机推荐

  • js中[]、{}、()区别

    一 大括号 表示定义一个对象 大部分情况下要有成对的属性和值 或是函数体 表示对象 表示对象的属性 方法 如果用在方法名后面 代表调用 如 var LangShen Name Langshen AGE 28 上面声明了一个名为 LangSh
  • 卷积产生的参数量(Parameters)和计算量(FLOPs)

    输入 H in W in C in Filter k k 输出 H out W out C out 进行一次卷积操作产生的参数量 Parameters 和计算量 FLOPs 为 Parameters k k C in C out FLOPs
  • C++STL详解(十) -- 使用哈希表封装unordered_set和unordered_map

    文章目录 哈希表模板参数改造 针对模板参数V改造 增加仿函数获取具体数据类型 哈希表的正向迭代器 正向迭代器中的内置成员 正向迭代器的成员函数 哈希表插入函数的修改 适用于unordered map 一个类型K去做set和unordered
  • xp系统web服务器不可用,WindowsXP系统无法使用火狐浏览器访问网页?教你解决方法...

    汽车中的SL SE和SX分别是什么 汽车中的SL即为该车为标准配置 低配62616964757a686964616fe78988e69d8331333433623732版 SE 即为高配版 SX是豪华版 汽车排量后边的这两个缩写字母 实际是
  • 二叉树中序遍历 (C语言实现)

    在计算机科学中 树是一种重要的非线性数据结构 直观地看 它是数据元素 在树中称为结点 按分支关系组织起来的结构 二叉树是每个节点最多有两个子树的有序树 通常子树被称作 左子树 left subtree 和 右子树 right subtree
  • ping不通的常见原因和解决办法

    Ping是Windows Unix和Linux系统下的一个命令 ping也属于一个通信协议 是TCP IP协议的一部分 利用 ping 命令可以检查网络是否连通 如果ping不通则可以通过以下方式寻找故障原因 1 ping 127 0 0
  • python 数据分析与可视化

    python数据分析及可视化 涉及内容 1 Pandas的Series数据类型的定义及相关操作函数 2 Pandas的DataFtame数据类型的定义及相关操作函数 3 Pandas的统计功能 4 Pandas的合并连接和排序 5 Pand
  • win10查看系统激活状态

    快捷键 win R 然后输入 slmgr vbs xpr 或者 slmgr vbs dlv
  • 基于SSM框架的CMS内容管理系统的设计与实现

    基于SSM框架的CMS内容管理系统的设计与实现 付源码 论文 工作任务 1 通过学习和查找相关的资料 掌握SpringMVC Spring Mybatis框架的搭建及开发 通过学习掌握freemarker BootStrap等前端模板引擎和
  • Qt 编写多窗口程序

    该文章原创于 Qter开源社区 www qter org 作者 yafeilinux 转载请注明出处 导语 程序要实现的功能是 程序开始出现一个对话框 按下按钮后便能进入主窗口 如果直接关闭这个对话框 便不能进入主窗口 整个程序也将退出 当
  • Java2023毕业设计诗词发布系统前后端分离(附下载链接)vue+Spring Boot+mybatis+sql+maven

    Java2023毕业设计诗词发布系统前后端分离 附资源下载链接含数据库文件 vue Spring Boot mybatis sql maven 注册 登录 查看个人信息 修改个人信息 诗词曲列表 搜索 诗词曲详情 评论列表 点赞与取消点赞
  • python实现:输出整数数组前半段非递减、后半段非递增并且从小到大不重复打印数字

    问题 给定一个正整数数组 前半段非递减 后半段非递增 要求从小到大不重复打印数字 给定时间复杂度O n 空间复杂度O 1 解题思路 分析 这道题 可以理解为合并两个有序数组 并且合并后的数组中 无相等的元素即可 基于时间复杂度和空间复杂度的
  • Linux命令学习 - Crontab【排错篇】

    Crontab 排错篇 文章目录 Crontab 排错篇 no crontab for root 查看Cron的日志 修改rsyslog文件 重启rsyslog服务 重启cron服务 查看日志文件 no crontab for root 当
  • Mac版office word保存后退出文件莫名被删除问题

    来源百度贴吧 http tieba baidu com p 3674902738 在mac terminal 中执行 sudo find name tmp 按提示输入密码 一般就是电脑开机密码 在 private var folders j
  • CentOS 7.5 搭建以太坊私联(联盟链)及区块链浏览器

    环境 操作系统为win10 虚拟化2个centos7 5 系统 cpu 4核 内存8G 本文将以node1 node2代表虚拟机节点1 和虚拟机节点2 此篇将搭建2个节点 node1 会搭建区块链浏览器 环境准备 node1 搭建 关闭防火
  • python(matplotlib)绘制y=x^2函数曲线和正弦曲线

    python matplotlib 绘图 这次绘制两个简单常见的图形 分别是y X 2曲线和正弦曲线 具体的案例如下所示 1 绘制要求 利用matplotlib库文件 画图函数y x 2的图形 绘制过程 import matplotlib
  • socket超时

    一 连接超时 这种超时在前面的例子中已经使用过 在Socket类中只有通过connect方法的第二个参数才能指定连接超时的时间 由于使用connect方法连接服务器必须要指定IP和端口 因此 无效的IP或端口将会引发连接超时错误 二 读取数
  • CompletableFuture异步编程

    1 前言 数据库中有订单表 而订单表分库分表了 查询起来要横跨库和表 比较麻烦 所以搞了搞异步编程 2 实现 因为分库是按照年份来分的 分表是按照月份来分的 所以我初步思考了一下 按月异步去查询 然后开启多线程异步查询 这样查询速度能成几何
  • 秒杀架构设计理念

    限流 鉴于只有少部分用户能够秒杀成功 所以要限制大部分流量 只允许少部分流量进入服务后端 削峰 对于秒杀系统瞬时会有大量用户涌入 所以在抢购一开始会有很高的瞬间峰值 高峰值流量是压垮系统很重要的原因 所以如何把瞬间的高流量变成一段时间平稳的
  • C++编程——继承

    文章目录 1 继承的基本语法 2 继承方式 3 继承的对象模型 4 继承中构造和析构顺序 5 继承中同名成员处理 6 继承中同名静态成员处理方式 6 1 通过对象访问 6 2 通过类名访问 7 多继承语法 7 1 多继承的对象模型 8 菱形