C++面向对象三大特征-----继承(详细版)

news2024/11/19 0:41:48

目录

继承

一、继承的基础介绍

普通版网页和继承版网页的区别

语法

二、继承方式

三种继承方式

三、继承中的对象模型

四、继承中构造和析构函数

五、继承同名成员的处理方式

访问同名成员:

作用域写法:

六、继承同名静态成员的处理方式

访问同名成员:

为什么能用类名访问静态成员?

静态成员:

静态成员函数:

总结:

七、多继承语法

语法:

八、菱形继承

概念:

菱形继承问题:

解决办法:

虚继承语法:

总结:


继承

一、继承的基础介绍

继承是面向对象三大特征之一

有些类和类之间存在特殊关系,如:

我们可以发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的个性。这个时候我们就可用继承的技术减少重复代码。 继承的基本语法 如很多网站中都有公共的头部,公共的底部,公共的左侧列表,只有中心内容不同,接下来用普通写法和继承写法来实现网页(我以CSDN的网页为例)中的内容,看一下继承存在的意义以及好处

普通版网页和继承版网页的区别

普通版网页

//普通版网页
class ZhuYe
{
public:
    void head()
    {
        cout << "博客  下载  学习  社区  C知道    GitCode InsCode" << endl;
    }
    void foot()
    {
        cout << "用户名 关注 收藏" << endl;
    }
    void left()
    {
        cout << "原创 周排名  总排名 访问" << endl;
    }
};
​
class Czhidao
{
public:
    void head()
    {
        cout << "博客  下载  学习  社区  C知道    GitCode InsCode" << endl;
    }
    void foot()
    {
        cout << "用户名 关注 收藏" << endl;
    }
    void context()
    {
        cout << "请输入你的问题" << endl;
    }
    void left()
    {
        cout << "原创 周排名  总排名 访问" << endl;
    }
​
};
​
​
class SheQu
{
public:
    void head()
    {
        cout << "博客  下载  学习  社区  C知道    GitCode InsCode" << endl;
    }
    void foot()
    {
        cout << "用户名 关注 收藏" << endl;
    }
    void context()
    {
        cout << "与我相关 最新发布 最新回复 最热 有活动 有问题" << endl;
    }
    void left()
    {
        cout << "原创 周排名  总排名 访问" << endl;
    }
​
};
​
void test01()
{
    ZhuYe a;
    a.head();
    a.foot();
    a.left();
    cout << "-------------------------" << endl;
​
    Czhidao b;
    b.head();
    b.context();
    b.foot();
    b.left();
    cout << "-------------------------" << endl;
​
    SheQu c;
    c.head();
    c.context();
    c.foot();
    c.left();
}
​
int main()
{
    test01();
    return 0;
}

其实会发现这个代码中有大量重复代码,这样子的代码是很Low的,也不符合C++是面向对象的语言的标准,而且会使得代码量加大,这个在企业开发中是一定要杜绝

继承版网页

//继承版网页
class ZhuYe
{
public:
    void head()
    {
        cout << "博客  下载  学习  社区  C知道    GitCode InsCode" << endl;
    }
    void foot()
    {
        cout << "用户名 关注 收藏" << endl;
    }
    void left()
    {
        cout << "原创 周排名  总排名 访问" << endl;
    }
};
​
class Czhidao : public ZhuYe
{
public:
    void context()
    {
        cout << "请输入你的问题" << endl;
    }
};
​
​
class SheQu : public ZhuYe
{
public:
    void context()
    {
        cout << "与我相关 最新发布 最新回复 最热 有活动 有问题" << endl;
    }
};
​
void test01()
{
    ZhuYe a;
    a.head();
    a.foot();
    a.left();
    cout << "-------------------------" << endl;
​
    Czhidao b;
    b.head();
    b.context();
    b.foot();
    b.left();
    cout << "-------------------------" << endl;
​
    SheQu c;
    c.head();
    c.context();
    c.foot();
    c.left();
}
​
int main()
{
    test01();
    return 0;
}

以上是继承版代码,可以看出来他将重复的部分给删掉了,这里用了继承这个语法,现在我来讲讲继承的语法

语法

语法:class 子类 : 继承方式 父类

子类:又称派生类

父类:又称基类

派生类中的成员包括两大部分 一类是从基类继承过来的,一类是自己增加的成员 从基类继承过来的表现其共性,而新增的成员体现了个性

二、继承方式

三种继承方式

公共继承

保护继承

**私有继承

从图可知:

父类中的私有成员,不管子类以哪种方式继承,都不可访问

就像父亲的银行卡密码,就算你是他儿子,他也不会告诉你,因为那是他的私有财产

三、继承中的对象模型

问题,从父类继承过来的成员,哪些属于子类中?

答案:

1.父类所有非静态成员属性都会被子类继承下去 2.父类中的成员属性是被编译器给隐藏了,因此是访问不到的,但是确实被继承下去了,大家可以用以下代码检测一下

class A
{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
};
​
class B : public A
{
public:
    int m_D;
};
​
int main()
{
    B test;
    cout << sizeof(test) << endl;
    return 0;
}

以上代码的答案是:16,虽然B只能访问A的m_A,m_B,加上自己的m_D,只有12个字节数,但是父类的m_C只是不可访问,不等于其不存在,因此,可以看出来子类继承了父类中所有非静态成员

四、继承中构造和析构函数

子类继承父类后,当创建子类对象,也会调用父类的构造函数

问题:父类和子类的构造和析构函数顺序谁先谁后?

大家可以通过以下代码来看看:

class A
{
public:
    A()
    {
        cout << "父类构造函数执行" << endl;
    }
    ~A()
    {
        cout << "父类析构函数函数执行" << endl;
    }
​
};
​
class B : public A
{
public:
    B()
    {
        cout << "子类构造函数执行" << endl;
    }
    ~B()
    {
        cout << "子类析构函数函数执行" << endl;
    }
​
};
​
int main()
{
    B test;
    return 0;
}

会发现继承中的构造和析构顺序如下: 先构造父类,再构造子类,析构的顺序与构造的顺序相反

五、继承同名成员的处理方式

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

访问同名成员:

访问子类同名成员 直接访问即可

访问父类类同名成员 需要加作用域

作用域写法:

对象名.父类::成员名

大家可以看看以下代码来理解

class A
{
public:
    int m_A = 10;
};
​
class B : public A
{
public:
    int m_A = 20;
};
​
​
int main()
{
    B test;
    cout << test.m_A << endl;
    cout << test.A::m_A << endl;
​
    return 0;
}

如果子类中出现与父类同名成员函数;要访问就要加作用域

六、继承同名静态成员的处理方式

继承同名静态成员在子类对象上如何访问? 静态成员和非静态成员出现同名,处理方式一致

访问同名成员:

访问子类同名成员 直接访问即可

访问父类类同名成员 需要加作用域

不过,静态成员有两种方式访问

通过对象

通过类名

第一种方法与非静态成员一样的方式,我就不过多赘述,我来讲讲第二种方式

为什么能用类名访问静态成员?

因为静态成员与静态成员函数在内存中都只有一份,所以所有对象都能直接访问他,因此只需要类名就能知道它具体的值

类名访问语法(以以下代码的访问为例)

class A
{
public:
    static int m_A;
};
int A::m_A = 10;
​
class B : public A
{
public:
    static int m_A;
};
int B::m_A = 20;
​
int main()
{
    cout << B::m_A << endl;
    cout << B::A::m_A << endl;
​
    return 0;
}

插入静态成员知识点:

静态成员:

类型前加static

类内声明,类外初始化,一定要初始(因为静态变量放在全局区,全局区在编译阶段就分配内存)

静态成员函数:

返回类型前加static

只可访问静态变量

总结:

同名静态成员处理方式和非静态处理方式一样,只不过有两种访问方式(对象,类名)

七、多继承语法

C++中允许一个类继承多个类

语法:

class 子类 : 继承方式 父类1,继承方式 父类2, 继承方式 父类3……

多继承可能会引发父类有同名成员出现,要加作用域区分,因为容易出错,所以C++实际开发中不建议用多继承,因此不作过多介绍

八、菱形继承

概念:

两个派生类继承同一个基类 ​ 又有某个类同时继承两个派生类

以下例子虽然不符合事实动物的来源,但是有利于理解,大家就理解概念就好

菱形继承问题:

1.羊继承了动物的数据,驼同样继承了动物的数据,当羊驼使用数据时,就会产生二义性

class Animal
{
public:
    int m_Age;
};
​
class Sheep:public Animal
{
public:
    int m_Age;
};
​
class Tuo :public Animal
{
public:
    int m_Age;
};
​
class SheepTuo :public Sheep, public Tuo
{
public:
    int m_Age;
};
​
​
void test()
{
    SheepTuo st;
    st.Sheep::m_Age = 20;
    st.Tuo::m_Age = 10;
}
​
int main()
{
    test();
    return 0;
}

以上代码就有二义性:羊驼的年龄应该是和羊一样为20岁,还是应该和驼一样为10岁呢?

2.羊驼继承的动物的数据继承了两份,这份数据我们只需要一份就行

解决办法:

利用虚继承,解决菱形继承的问题

虚继承语法:

在继承之前加上关键字virtual变成虚继承

class Animal
{
public:
    int m_Age;
};
​
class Sheep:virtual public Animal
{
public:
    int m_Age;
};
​
class Tuo :virtual public Animal
{
public:
    int m_Age;
};
​
class SheepTuo :public Sheep, public Tuo
{
public:
    int m_Age;
};
​
​
void test()
{
    SheepTuo st;
    st.Sheep::m_Age = 20;
    st.Tuo::m_Age = 10;
}
​
int main()
{
    test();
    return 0;
}

这时你

cout << st.m_Age << endl;
cout << st.Sheep::m_Age << endl;
cout << st.Tuo::m_Age << endl;

都是等于10,因为三者在实际上时共用了一个数据,这里涉及了虚拟基类指针和虚拟基类表,这里涉及开发命令页的操作来展现,大家感兴趣的可以自行查找相关资料

总结:

菱形继承带来的主要问题是:子类继承两份相同的数据导致资源浪费以及毫无意义 可以用虚拟继承方式解决

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通讯录的模拟实现(C语言)

通讯录要求&#xff1a; 1&#xff0c;联系人要拥有姓名。年龄。性别&#xff0c;电话&#xff0c;地址 2&#xff0c;拥有增加&#xff0c;删除&#xff0c;搜索&#xff0c;修改&#xff0c;展示&#xff08;所有联系人&#xff09;&#xff0c;退出功能 3&#xff0c;能存…

力扣49. 字母异位词分组

Problem: 49. 字母异位词分组 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.以字符串作为键&#xff0c;与该键是字母异位词所组成的数组为值创建map集合&#xff1b; 2.每次取出一个字符串将其排序&#xff0c;再存入对应的数组&#xff1b; 3.将map中的值存…

VSGitHub项目联动(上传和克隆),创建你的第一个仓库,小白配置

目录&#xff1a; 前言一&#xff0c;基本说明1.1名词概念1.2必配条件 二&#xff0c;配置方法2.1本地生成密钥2.2云端代码托管平台SSH配置添加&#xff08;GitHub&#xff09;2.3VS项目配置 三&#xff0c;参考四&#xff0c;一些讨论 前言 &#x1f308;在编写VS代码项目时&a…

containerd源代码分析: 整体架构

本文从代码的大的整体组织上来熟悉containerd项目 containerd项目总的说是一个cs模式的原生控制台程序组。containerd作为服务端来接收处理client的各种请求&#xff0c;如常用的拉取推送镜像&#xff0c;创建查询停止容器&#xff0c;生成快照&#xff0c;发送消息等。client/…

程序设计语言+嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 1、嵌入式系统开发与设计 1.1嵌入式应用程序的生成与加…

在线获取文本列表并集计算器

具体请前往&#xff1a;在线文本并集计算工具

rabbitmq 3.9.29 docker mac 管理员页面无法打开

SyntaxError: Unexpected token ‘catch’ SyntaxError: Unexpected token ‘catch’ at EJS.Compiler.compile (http://127.0.0.1:15672/js/ejs-1.0.min.js:1:6659) at new EJS (http://127.0.0.1:15672/js/ejs-1.0.min.js:1:1625) at format (http://127.0.0.1:15672/js/main…

【Flask】Flask数据迁移操作

Flask数据迁移操作 前提条件 安装第三方包&#xff1a; # ORM pip install flask-sqlalchemy # 数据迁移 pip install flask-migrate # MySQL驱动 pip install pymysql # 安装失败&#xff0c;指定如下镜像源即可 # pip install flask-sqlalchemy https://pypi.tuna.tsinghu…

【Docker】golang操作容器使用rename动态更新容器的名字

【Docker】golang操作容器使用rename动态更新容器的名字 大家好 我是寸铁&#x1f44a; 总结了一篇golang操作容器使用rename动态更新容器的名字✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天遇到一个新的需求&#xff0c;要动态改变运行中的容器名字。 可以考虑先把…

鸿蒙实战开发-如何通过拖动滑块调节应用内字体大小

介绍 本篇Codelab将介绍如何使用基础组件Slider&#xff0c;通过拖动滑块调节应用内字体大小。要求完成以下功能&#xff1a; 实现两个页面的UX&#xff1a;主页面和字体大小调节页面。拖动滑块改变字体大小系数&#xff0c;列表页和调节页面字体大小同步变化。往右拖动滑块字…

Redis 教程系列之Redis 安装(二)

Windows 下安装 下载地址:Releases tporadowski/redis GitHub。 Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 C 盘,解压后,将文件夹重新命名为 redis。 打开文件夹,内容如下: 打开一个 cmd 窗口 使用 c…

更改Ubuntu桌面环境

功能异常 1&#xff1a; Ubuntu 22.04 将桌面 .desktop文件&#xff0c;用鼠标拖动到左侧的收藏夹菜单栏&#xff1a;无法实现&#xff0c;且会造成原来的 .desktop文件异常失效。 在多桌面环境下&#xff0c;切换到 KDE桌面&#xff0c;桌面 .desktop文件则是正常 OK的。 都 …

使用 PyOpenGL 进行 2D 图形渲染总结

一、说明 OpenGL是一个广泛使用的开放式跨平台实时 3D 图形库&#xff0c;开发于二十多年前。它提供了一个低级API&#xff0c;允许开发人员以统一的方式访问图形硬件。在开发需要硬件加速且需要在不同平台上运行的复杂 2D 或 3D 应用程序时&#xff0c;它是首选平台。它可以在…

CSS3 中的盒模型:标准与IE盒模型的差异

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

pytest之统一接口请求封装

pytest之统一接口请求封装 pytest的requests_util.pyrequests_util.py 接口自动化测试框架的封装yaml文件如何实现接口关联封装yaml文件如何实现动态参数的处理yaml文件如何实现文件上传有参数化时候&#xff0c;怎么实现断言yaml的数据量大怎么处理接口自动化框架的扩展&#…

谷歌seo营销服务有哪些服务?

以我们举例&#xff0c;如果你在做B2B外贸建站&#xff0c;这里有全套保姆式托管服务&#xff0c;让你既省心又省力&#xff0c;七天就能搞定网站建设&#xff0c;快速上线&#xff0c;再来就是谷歌白帽SEO&#xff0c;我们这边强调的是纯白帽操作&#xff0c;专注于高质量的原…

linux源配置:ubuntu、centos;lspci与lsmod命令区别

1、ubuntu源配置 1&#xff09;先查电脑版本型号: lsb_release -c2&#xff09;再编辑源更新&#xff0c;源要与上面型号对应 参考&#xff1a;https://midoq.github.io/2022/05/30/Ubuntu20-04%E6%9B%B4%E6%8D%A2%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90/ /etc/apt/…

基于springboot+vue的旅游网站

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

CICD流水线(ali)

后端CICD 一、打开云效流水线&#xff0c;创建流水线

全球大型语言模型(LLMS)现状与比较

我用上个博文的工具将一篇ppt转换成了图片&#xff0c;现分享给各位看官。 第一部分&#xff1a;国外大语言模型介绍 1&#xff0c;openai的Chatgpt 免费使用方法1&#xff1a;choose-carhttps://share.freegpts.org/list 免费使用方法2&#xff1a;Shared Chathttps://share…