【C++】继承(inheritance)

引入

假设我们有一个动物类

class Animal {
public:int age;void eat() {std::cout << "吃东西!" << std::endl;}
};

又想写一个狗类,它也有年龄,也会吃,除此之外还有种类

class Dog {
public:const char* kind;int age;void eat() {std::cout << "吃东西!" << std::endl;}
};

我们发现有重复的代码,如果我们写猫类、鸟类等都要再写一遍,这样很麻烦

那么有没有一种方法能提高代码的复用性,不需要再写一遍就能达到同样的效果呢?

我们让Dog继承Animal

#include<iostream>
class Animal {
public:int age;void eat() {std::cout << "吃东西!" << std::endl;}
};
class Dog :public Animal {
public:const char* kind;
};
int main() {Dog dog;dog.kind = "柯基";dog.age = 3;dog.eat();
}

没有写那部分重复代码却也能给age赋值,调用eat()方法

也就是说,Dog继承了Animal,Animal所拥有的age和eat()它也就有了,就像父亲遗传给儿子一样

  • Animal就叫做父类或者基类
  • Dog就叫做子类或者派生类

而且,狗本来就属于动物,我们让其继承动物也是符合思维的

单继承和多继承

class A {
};
class B :public A {//单继承
};
class D {
};
class E {
};
class F :public D, public E {//多继承
};

那么,子类继承父类后,父类的所有内容都能被子类访问吗?

继承方式

我们看到上面的继承有"public",这其实是继承方式

继承方式就是类中的三种访问属性,每种访问属性通过继承方式之后在派生类中可能会有新的属性

  1. 基类私有成员,不管用什么方式继承,都不能被访问
  2. 其他的成员访问属性和继承方式,两者看谁更严格就按严格的来:public<protected<private
基类成员的访问控制public继承protected继承private继承
private可以继承,但不可以访问可以继承,但不可以访问可以继承,但不可以访问
protectedprotectedprotectedprivate
publicpublicprotectedprivate

派生类的构成

  1. 派生类会继承除基类的构造析构函数之外的所有成员变量和成员函数
  2. 可以在派生类中添加新的成员,通过派生类对象来调用
  3. 如果派生类中添加的成员名和基类成员名相同,那么派生类会隐藏基类的成员,可以通过.基类名::基类成员名来访问。如果是继承的多个基类,而多个基类中也有同名的,也是通过此种方式调用同名的成员。子类对象直接访问同名成员,访问的是子类对象自己的同名成员。

示例:

#include<iostream>
class Animal {
public:int age;void eat() {std::cout << "吃东西!" << std::endl;}
};
class Dog :public Animal {
public:const char* kind;void eat() {std::cout << "啃骨头!" << std::endl;}
};
int main() {Dog dog;dog.eat();dog.Animal::eat();
}

派生类和基类的关系

子类不包含父类,而是子类中有父类的所有数据成员和函数成员(除构造析构)。派生类是基类对象,但是基类不是派生类对象;派生类可以赋值给基类,而基类不能给派生类赋值。

派生类的构造析构顺序

  1. 派生类对象在实例化的时候是会调用基类的构造函数的,先基类后派生类(先有父亲后有儿子),释放就是先儿子后父亲,因为栈结构(先进后出)
  2. 如果是多继承,其与单继承中构造顺序一致;区别在于,在构造基类时有多个基类,那么会按照基类的继承声明顺序来依次调用基类的构造函数,然后构造子对象,最后构造自己
  3. 在写继承的时候,要确保基类有可以调用的构造函数
  4. 带参构造:在构造过程中,如果基类或子对象需要参数来进行构造,就需要通过成员初始化列表来构造

示例1:

#include<iostream>
class A {
public:A() {std::cout << "调用A的无参构造" << std::endl;}A(int a) {std::cout << "调用A的有参构造" << std::endl;}~A() {std::cout << "调用A的析构" << std::endl;}
};
class B :public A {
public:B() {std::cout << "调用B的无参构造" << std::endl;}B(int b) {std::cout << "调用B的有参构造" << std::endl;}~B() {std::cout << "调用B的析构" << std::endl;}
};
int main() {B b1;B b2(5);
}

运行结果:

调用A的无参构造
调用B的无参构造
调用A的无参构造
调用B的有参构造
调用B的析构
调用A的析构
调用B的析构
调用A的析构

示例2:

#include<iostream>
class A {
public:A(int a) {std::cout << a << std::endl;}
};
class B :public A {
public:B():A(1){}//在初始化列表中调用父类的带参构造//不这样写直接实例化会报错
};
int main() {B b1;
}

派生类的内存大小

  • 派生类的内存大小=所有父类内存大小之和+本身新增的成员内存大小
  • 派生类的内存中,基类的内存在最低位,派生类的内存在最高位

菱形继承

菱形继承

类B,C分别继承A;类D继承类B,C

这样继承会导致类D继承两份类A的成员,在类D对象,想要访问类A的成员的时候,会导致访问不明确。因为类B,C各自继承类A的成员

解决方法

(1)通过类名::成员名来确定调用哪个成员(不常用)

(2)通过虚继承,在继承方式的前面加上关键字virtual,虚继承之后会使在虚继承的类中多个指针(内存就会变大),但是在最后的D类,不会再继承两份A的成员了

示例1:

#include<iostream>
class A {int a = 1;
};
class B :public A {int c = 2;
};
class C :public A {int d = 3;
};
class D :public B, public C {int e = 4;
};
int main() {std::cout << sizeof(A) << std::endl;//4std::cout << sizeof(B) << std::endl;//8std::cout << sizeof(C) << std::endl;//8std::cout << sizeof(D) << std::endl;//20
}

示例2:

#include<iostream>
class A {int a = 1;
};
class B :virtual public A {int c = 2;
};
class C :virtual public A {int d = 3;
};
class D :public B, public C {int e = 4;
};
int main() {std::cout << sizeof(A) << std::endl;//32位:4	64位:4std::cout << sizeof(B) << std::endl;//32位:12	64位:24std::cout << sizeof(C) << std::endl;//32位:12	64位:24std::cout << sizeof(D) << std::endl;//32位:24	64位:48
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/477363.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(二)

Oracle - 多区间按权重取值逻辑 &#xff0c;分时区-多层级-取配置方案https://blog.csdn.net/shijianduan1/article/details/133386281 某业务配置表&#xff0c;按配置的时间区间及组织层级取方案&#xff0c;形成报表展示出所有部门方案的取值&#xff1b; 例如&#xff0…

电子应用设计方案-19:智能云饭锅系统方案设计

智能云饭锅系统方案设计 一、系统概述 本智能云饭锅系统旨在提供便捷、个性化和智能化的烹饪体验&#xff0c;结合云服务实现远程控制、食谱推荐和烹饪数据管理等功能。 二、系统组成 1. 锅体 - 采用高品质的不粘涂层内胆&#xff0c;确保米饭受热均匀且易于清洁。 - 具备良好…

镁光MT25QU01GXXX norflash调试笔记

目录 前言一、芯片概述二、数据手册解释1. 数据手册获取2.内容概括 三、几个操作的代码1.复位芯片操作2.读取芯片ID3.擦除芯片扇区4.向芯片存入数据5.读取存储的数据6.其它操作函数 前言 本笔记总结如何使用MCU对nor flash进行数据存储&#xff0c;包括芯片基本介绍&#xff0…

Qt界面设计时使各控件依据窗口缩放进行栅格布局的方法

图1 最终效果 想要达成上述图片的布局效果&#xff0c;具体操作如下&#xff1a; 新建一窗体&#xff1a; 所需控件如下&#xff1a; Table View控件一个&#xff1b; Group Box控件一个&#xff1b; Push Button控件2个&#xff1b; Horiziontal Spacer控件2个&#xf…

【Git】:Git基本操作

目录 创建、配置本地仓库 创建本地仓库 配置本地仓库 认识工作区、暂存区、版本库 修改文件 版本回退 撤销修改 删除文件 创建、配置本地仓库 创建本地仓库 我们通常可以通过以下两种方式之一获取 Git 存储库&#xff1a; 自己在本地目录创建一个本地仓库 从其它服务…

CANDENCE: 绘制好的封装元件 刷新(Refresh) 和 替换 (Replace)焊盘

绘制好的封装元件 刷新(Refresh) 和 替换 &#xff08;Replace&#xff09;焊盘 一、刷新(Refresh) 1、以下面这个bga484封装的元件为例 2、打开bga的焊盘文件 3、我们对上面这个焊盘稍加修改&#xff0c;如下&#xff0c;然后保存 4、在封装编辑页面&#xff0c;如下操作 5…

HarmonyOS:使用ArkWeb构建页面

一、简介 页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景&#xff0c;包括加载网络页面、加载本地页面、加载HTML格式的富文本数据。 页面加载过程中&#xff0c;若涉及网络资源获取&#xff0c;需要配置ohos.permission.INTERNET网络访问权限。 二、…

修改一下达梦disql 提示符

经常用disql的有时某些信息希望提示一下&#xff0c;默认的只显示SQL> 为了方便使用&#xff0c;可以在 glogin.sql 中增加些内容。 vi $DM_HOME/bin/disql_conf/glogin.sql增加以下几行 set time on set lineshow offcol global_name new_value global_name SELECT ins…

跨境出海安全:如何防止PayPal账户被风控?

今天咱们聊聊那些让人头疼的事儿——PayPal账户被风控。不少跨境电商商家反馈&#xff0c;我们只是想要安安静静地在网上做个小生意&#xff0c;结果不知道为什么&#xff0c;莫名其妙账户就被冻结了。 但其实每个封禁都是有原因的&#xff0c;今天就来给大家分享分享可能的原…

如何读论文【论文精读·1】

第一遍题目 摘要 结论 方法 实验 是不是适合自己看看自己适不适合这篇文章。&#xff08;花时最少&#xff0c;做海选&#xff09; 不需要懂太具体的公式。这一遍阅读之后&#xff0c;你需要再继续思考一下这篇论文的质量以及和自己研究方向的契合程度&#xff0c;决定一下自己…

【模块一】kubernetes容器编排进阶实战之pod生命周期、探针简介、类型及示例

kubernetes pod生命周期、探针简介、类型及示例 kubernetes pod生命周期 pod的生命周期(pod lifecycle)&#xff0c;从pod start时候可以配置postStart检测&#xff0c;运行过程中可以配置livenessProbe和 readinessProbe,最后在 stop前可以配置preStop操作 探针简介 探针是由…

医学AI公开课·第一期|Machine LearningTransformers in Med AI

小罗碎碎念 从这周开始&#xff0c;我计划每个周末录一个视频&#xff0c;分享一些医学人工智能领域的进展。 作为第一期视频&#xff0c;我打算介绍一下机器学习和Transformer在医学AI领域中的应用。 为了准备这期视频&#xff0c;总共做了24页PPT&#xff08;三部分内容&…

[代码随想录Day21打卡] 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 总结篇

669. 修剪二叉搜索树 给定一个二叉搜索树root&#xff0c;给定一个范围[low, high]&#xff0c;修剪二叉搜索树&#xff0c;使修建后的二叉搜索树的值的范围在[low, high]内。 思想&#xff1a;当前节点的值和给定的范围之间的关系&#xff0c;如果当前节点的值大于high那么就…

apr共享内存

下载&#xff1a; Download - The Apache Portable Runtime Project 编译&#xff1a; 使用cmake-gui生成库&#xff1a; apr-1.lib aprapp-1.lib libapr-1.lib libaprapp-1.lib libapr-1.dll 在Developer PowerShell for VS 2019中&#xff1a; 执行nmake -f Makefile.win来…

借助算力云跑模型

算力平台&#xff1a;FunHPC | 算力简单易用 AI乐趣丛生 该文章只讲述了最基本的使用步骤&#xff08;因为我也不熟练&#xff09;。 【注】&#xff1a;进入平台&#xff0c;注册登录账号后&#xff0c;才能租用。学生认证&#xff0b;实名认证会有免费的算力资源&#xff0…

聚水潭与MySQL数据集成案例分享

聚水潭数据集成到MySQL的技术案例分享 在现代数据驱动的业务环境中&#xff0c;如何高效、可靠地实现不同系统之间的数据对接成为企业关注的焦点。本次案例将详细介绍如何通过轻易云数据集成平台&#xff0c;将聚水潭的数据无缝集成到MySQL数据库中&#xff0c;实现从“聚水谭…

C语言中const char *字符进行切割实现

将127.0.0.1以“”“.”来进行切割&#xff0c;实现如下&#xff1a; const char * ip "127.0.0.1";char *test new char[100];strcpy(test, ip);const char *split ".";char *final;final strtok(test, split);while (final){printf("%s\n"…

java基础知识(常用类)

一、包装类&#xff08;Wrapper) &#xff08;1&#xff09;包装类与基本数据的转换 装箱&#xff1a;基本类型->包装类型 拆箱&#xff1a;包装类型->基本类型 java5以后是自动装箱和拆箱的方式&#xff0c;自动装箱底层调用的是valueOf方法&#xff0c;比如Integer.…

【Python系列】字典灵活的数据存储与操作

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

neo4j图数据库community-5.50创建多个数据库————————————————

1.找到neo4J中的conf文件&#xff0c;我的路径是&#xff1a;D:\Program Files\neo4j-community-5.5.0-windows\neo4j-community-5.5.0\conf 这里找自己的安装路径&#xff0c; 2.用管理员模式打开conf文件&#xff0c;右键管理员&#xff0c;记事本或者not 3.选中的一行新建一…