[第五天】C++继承:单继承、多继承、菱形继承和虚继承的深度解析

一、单继承

1、概述

        C++最重要的特征是代码重用,通过继承机制可以利用已有的数据类型来定义新的数据类型,新的类不仅拥有旧类的成员,还拥有新定义的成员。

        例如一个B类继承于A类,或称从类A派生类B。这样的话,类A成为基类(父类),类B成为派生类(子类)。派生类中的成员,包含两大部分:一类是从基类继承过来的,一类是自己增加的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。

 2、子类的定义形式

定义形式:

class 父类{};
class 子类:继承方式 父类名
{//新增子类数据
};

继承方式:private protected public(推荐) 

公共继承 保持不变,保护继承变保护,私有继承变私有,所有父类私有在子类中不可见。 

 以public为例:

3、子类的构造析够顺序

class Base
{
public:Base(){cout<<"父类构造函数"<<endl;}~Base(){cout<<"父类析构函数"<<endl;}
};
class Other
{
public:Other(){cout<<"Other构造函数"<<endl;}~Other(){cout<<"Other析构函数"<<endl;}
};
class Son :public Base
{
public:Other ob;
public:Son(){cout<<"子类构造函数"<<endl;}~Son(){cout<<"子类析构函数"<<endl;}
};
void test()
{Son ob;
}

 运行结果:

4、子类调用成员对象和父类的有参构造

一般情况下,子类 会自动调用 成员对象和父类的默认构造

调用成员对象和父类的有参构造:子类 必须使用有参构造初始化列表 

初始化列表时:父类类名称成员对象对象名

#include<iostream>
#include<string>
using namespace std;
class Base
{
public:int a;
public:Base(){cout << "父类默认构造函数" << endl;}Base(int a){this->a = a;cout << "父类有参构造函数" << endl;}~Base(){cout << "父类析构函数" << endl;}
};
class Other
{
public:int b;
public:Other(){cout << "Other默认构造函数" << endl;}Other(int b){this->b = b;cout << "Other有参构造函数" << endl;}~Other(){cout << "Other析构函数" << endl;}
};
class Son :public Base
{
public:int c;Other ob;
public:Son(){cout << "子类默认构造函数" << endl;}//子类要给成员中b赋值,父类中的a赋值//不能直接赋值,父类会先执行存在,调用父类默认构造Son(int a,int b,int c):Base(a),ob(b)//用初始化列表,父类写类名称 成员对象用对象名{this->c=c;cout << "子类有参构造函数" << endl;}~Son(){cout << "子类析构函数" << endl;}
};
void test()
{Son ob(10,20,30);
}
int main(int argc, char* argv[])
{test();return 0;
}

 5、子类和父类同名成员处理

处理方式:加作用域

1、子类和父类 同名成员数据

        默认优先访问 子类的同名成员,加父类作用域 访问父类的同名成员。

2、子类和父类 同名成员函数

 注:子类会重定义父类的同名函数:

重载:无继承,同一作用域,参数的个数、顺序、类型不同 都可重载

重定义:有继承, 子类 重定义 父类的同名函数(参数可以不同)(非虚函数)

        子类一旦 重定义了父类的同名函数(不管参数是否一致),子类中都将屏蔽父类所有的同名函数。必须加父类作用域 访问父类的同名成员。

class Base
{
public:void fun(){cout<<"父类fun函数"<<endl;}void fun(int a){cout<<"父类带一个参数fun函数"<<endl;}void fun(int a,int b){cout<<"父类带两个参数fun函数"<<endl;}
};
class Son :public Base
{
public:void fun(){cout<<"子类fun函数"<<endl;}
};
void test()
{Son ob;//类默认优先访问 子类的同名成员ob.fun();//必须加父类作用域 访问父类的同名成员ob.Base::fun(10);//OB.fun(10);会报错ob.Base::fun(10,20);
}

6、子类不能继承的父类成员

父类的构造析够重载赋值运算符operator= 不能被子类 继承。

二、多继承

1、多继承的格式

class 父类1{};
class 父类2{};class 子类:继承方式1 父类1, 继承方式2 父类2
{//新增子类数据
};

子类拥有父类1,父类2的大部分数据

2、多继承中同名成员 

 三、菱形继承

        两个派生类继承同一个基类而又有某个类同时继承者两个派生类,即有公共祖先的继承。这种继承被称为菱形继承,或者钻石型继承。

        最底层的子类 数据 会包含多份公共祖先的数据和基类派生的派生类的数据

         

 形象图:

问题: 

         1、羊继承了动物的数据和函数,鸵同样继承了动物的数据和函数,当草泥马调用函数或者数据时,就会产生二义性,通过加作用域解决。

        2、草泥马继承自动物的函数和数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以,通过虚继承解决。

class Animal
{
public:int Data;
};
class Sheep:public Animal{};
class Tuo:public Animal{};
class SheepTuo:public Sheep,public Tuo{};void test()
{SheepTuo ob;//cout<<ob.Data;二义性报错cout<<ob.Sheep::Data<<endl;cout<<ob.Tuo::Data<<endl;
}

四、虚继承 

        虚继承 解决 菱形继承中 多份公共祖先数据的问题

1、虚继承的概述

        子类虚继承父类 子类只会保存一份公共数据。

        方式:在继承方式 前加virtual修饰

2、分析虚继承的实现原理(vs端) 

从电脑开始中的目录找找到 Developer Command Prompt for VS 2022 并打开

在vs复制完整路径后进入对应文件夹。

dir命令查看文件 

 

 导出单个类的布局:

cl /d1 reportSingleClassLayoutAnimal main.cpp

Sheep布局: 

Tuo布局:

SheepTuo布局:

         虚继承 会在子类中产生 虚基类指针(vbptr) 指向 虚基类表(vbtable), 虚基类表纪录的是 通过该指针访问公共祖先的数据的偏移量。

 注意:

1、虚继承只能解决具备公共祖先的多继承所带来的二义性问题,不能解决没有公共祖先的 多继承的

2、工程开发中真正意义上的多继承是几乎不被使用,因为多重继承带来的代码复杂性远多 于其带来的便利,多重继承对代码维护性上的影响是灾难性的,在设计方法上,任何多继承 都可以用单继承代替

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

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

相关文章

(四)elasticsearch 源码之索引流程分析

https://www.cnblogs.com/darcy-yuan/p/17024341.html 1.概览 前面我们讨论了es是如何启动&#xff0c;本文研究下es是如何索引文档的。 下面是启动流程图&#xff0c;我们按照流程图的顺序依次描述。 其中主要类的关系如下: 2. 索引流程 (primary) 我们用postman发送请求&…

Navicat的使用教程,操作详解

这篇文章主要针对mysql数据库。 在使用Navicat之前&#xff0c;首先要确保你在本地已经安装好了&#xff0c;mysql数据库&#xff0c;安装教程可以参考我的另一篇博文 在windows平台上mysql的安装教程-CSDN博客 1.Navicat连接你的数据库 连接名&#xff0c;随便写&#xff0c…

游戏服务器购买多少钱1个月?买一年贵吗?

游戏服务器购买多少钱1个月&#xff1f;阿里云26元1个月、腾讯云32元1个月。买一年贵吗&#xff1f;不贵。 游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4…

mvn常见报错:Failed to read artifact descriptor for 解决

问题&#xff1a; mvn打包时报错&#xff1a;Failed to read artifact descriptor for 产生原因&#xff1a; 项目打包时所需的依赖包不存在本地仓库&#xff0c;或本地仓库文件存在问题。 解决方法&#xff1a; 检查仓库可用性&#xff1a; 确保在Maven设置或pom.xml中指定…

homeword_day1

第一章 命名空间 一&#xff0e;选择题 1、编写C程序一般需经过的几个步骤依次是&#xff08; B &#xff09; A. 编辑、调试、编译、连接 B. 编辑、编译、连接、运行 C. 编译、调试、编辑、连接 D. 编译、编辑、连接、运行 2、所谓数据封装就是将一组数据和与这组数据…

高清符合要求的SCI图片使用RStudio导出

4.图片格式区别和常识 在计算机中&#xff0c;JPEG&#xff08;发音为jay-peg, IPA&#xff1a;[ˈdʒeɪpɛg]&#xff09;是一种针对照片视频而广泛使用的有损压缩标准方法。这个名称代表Joint Photographic Experts Group&#xff08;联合图像专家小组&#xff09;。此团队创…

掼蛋技巧-组牌

掼蛋时&#xff0c;自己手中的牌是一定的&#xff0c;不变的&#xff0c;但是牌型是可以调整变化的。相同的牌&#xff0c;不同的牌型组合&#xff0c;牌的力量效果往往是不同的&#xff0c;甚至相差甚远。 组牌就是为了使牌型组合更加优化&#xff0c;从而对自己更加有利&…

Python 数据分析(PYDA)第三版(五)

原文&#xff1a;wesmckinney.com/book/ 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 十、数据聚合和组操作 原文&#xff1a;wesmckinney.com/book/data-aggregation 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 此开放访问网络版本的《Python 数据分析…

JAVA字节流的两个重要子类FileOutputStream、FileInputStream

字节流&#xff0c;字符集&#xff0c;字符流 因为它们都是抽象类&#xff0c;所以要学习它们的子类 字节流的结构: FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写入本地文件。 书写步骤&#xff1a; 创建字节输出流对象写数据释放资源 演示:…

sqli-labs-master靶场训练笔记(38-53|boss战)

2024.2.4 level-38 &#xff08;堆叠注入&#xff09; 这题乍一看感觉又是来卖萌的&#xff0c;这不是和level-1一模一样吗 然后仔细看了一下源代码&#xff0c;根据 mysqli_multi_query 猜测这题的本意应该是堆叠注入 mysqli_multi_query() 是 PHP 中用于执行多个 SQL 查…

54.替换数字(卡码网KamaCoder)

文章目录 54.替换数字题目描述暴力双指针 54.替换数字 题目描述 给定一个字符串 s&#xff0c;它包含小写字母和数字字符&#xff0c;请编写一个函数&#xff0c;将字符串中的字母字符保持不变&#xff0c;而将每个数字字符替换为number。 例如&#xff0c;对于输入字符串 “…

AUTOSAR CP--chapter2Autosar简介

Autosar简介 安全&#xff1a;使用严格的标准化去约束&#xff1b; 高效&#xff1a;通过提高软件模块的可移植性和复用性来提升&#xff1b; 灵活&#xff1a;通过上位机剪裁配置&#xff0c;自动生辰的手段来实现。 Autosar标准从行业高度统一了各个角色间的分工、接口以及方…