C++进阶之路---继承(二)

顾得泉:个人主页

个人专栏:《Linux操作系统》 《C++从入门到精通》  《LeedCode刷题》

键盘敲烂,年薪百万!


一、继承与友元

       友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员

class Student;
class Person
{
public:
     friend void Display(const Person& p, const Student& s);
protected:
     string _name; // 姓名
};
class Student : public Person
{
protected:
     int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
     cout << p._name << endl;
     cout << s._stuNum << endl;
}
void main()
{
     Person p;
     Student s;
     Display(p, s);
}

       当我们把这段代码放入VS中,我们可以看到:

       用通俗的话语来说:你爸爸的朋友不一定是你的朋友,哈哈。


二、继承与静态成员

       基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例

class Person
{
public :
     Person () {++ _count ;}
protected :
     string _name ; // 姓名
public :
     static int _count; // 统计人的个数。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
     int _stuNum ; // 学号
};
class Graduate : public Student
{
protected :
     string _seminarCourse ; // 研究科目
};
void TestPerson()
{
     Student s1 ;
     Student s2 ;
     Student s3 ;
     Graduate s4 ;
     cout <<" 人数 :"<< Person ::_count << endl;
     Student ::_count = 0;
     cout <<" 人数 :"<< Person ::_count << endl;
}

由结果可得: 

         


三、复杂的菱形继承及菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

 菱形继承:菱形继承是多继承的一种特殊情况。

 菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在Assistant的对象中Person成员会有两份。

class Person
{
public :
     string _name ; // 姓名
};
class Student : public Person
{
protected :
     int _num ; //学号
};
class Teacher : public Person
{
protected :
     int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
     string _majorCourse ; // 主修课程
};
void Test ()
{
     // 这样会有二义性无法明确知道访问的是哪一个
     Assistant a ;
     a._name = "peter";
     // 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
     a.Student::_name = "xxx";
     a.Teacher::_name = "yyy";
 }

       虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。

 

虚拟继承解决数据冗余和二义性的原理

       为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系,再借助内存窗口观察对象成员的模型。

class A
{
public:
     int _a;
};
// class B : public A
class B : virtual public A
{
public:
     int _b;
};
// class C : public A
class C : virtual public A
{
public:
     int _c;
};
class D : public B, public C
{
public:
     int _d;
};
int main()
{
     D d;
     d.B::_a = 1;
     d.C::_a = 2;
     d._b = 3;
     d._c = 4;
     d._d = 5;
     return 0;
}

       下图是菱形继承的内存对象成员模型:这里可以看到数据冗余

 

       下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。

下面是上面的Person关系菱形虚拟继承的原理解释:


四、继承的总结和反思

     1.很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设计出菱形继承。否则在复杂度及性能上都有问题

     2.多继承可以认为是C++的缺陷之一,很多后来的OO语言都没有多继承,如Java。

     3.继承和组合

        ①public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
        ②组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
        ③优先使用对象组合,而不是类继承
        ④继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。
        ⑤对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。
       ⑥ 实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用继承,可以用组合,就用组合。


结语:C++关于继承的分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[C语言]——分支和循环(4)

目录 一.随机数生成 1.rand 2.srand 3.time 4.设置随机数的范围 猜数字游戏实现 写⼀个猜数字游戏 游戏要求&#xff1a; &#xff08;1&#xff09;电脑自动生成1~100的随机数 &#xff08;2&#xff09;玩家猜数字&#xff0c;猜数字的过程中&#xff0c;根据猜测数据的⼤…

【LaTeX】行内代码块、行间代码块的插入以及高亮(懒人版)

文章目录 思路和优点基本框架行内代码行间代码pythoncpp 所支持的语言所支持的代码风格 思路和优点 思路是listingsminted包&#xff0c; 一个负责插入代码一个负责高亮代码 这种方法显著的优点在于&#xff1a;完全不需要自定义代码风格 使用其他方法时&#xff0c;你定义好…

嵌入式学习36-TCP要点及http协议

TCP发送文件的粘包问题 1. 例&#xff1a; 发端 1.flv-------->收端 1.flv csfga 2.解决 1. sleep&#xff08;1&#xff09; 延时发送 2.自…

httprunner用例结构(前后置)

说明&#xff1a;httprunner 结合 pytest 的前后置方式 1. 用例级别前后置 1.1. setup teardown class TestCaseRefTestcase(HttpRunner):# 用例级别前后置def setup(self):logger.warning("------用例级别前置")def teardown(self):logger.warning("------用…

用一个 Python 脚本实现依次运行其他多个带 argparse 命令行参数的 .py 文件

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 问题描述&#xff1a;在 Windows 环境中&#xff0c;您希望通过一个 Python 脚本来实现特定的自动化任务&#xff0c;该任务需要依次运行其他多个带 argparse 命令行参数的 .py 文件。您希望找到一种简…

【jenkins】简单安装及配置(Windows环境)

前言 jenkins是一款跨平台的持续集成和持续交付、基于Java开发的开源软件&#xff0c;提供任务构建、持续集成监控的功能&#xff0c;可以使开发测试人员更方便的构建软件项目&#xff0c; 提高工作效率。Windows平台下&#xff0c;一般安装方法有2种&#xff1a;安装程序安装…

unicloud where 使用

where介绍 在uniCloud中&#xff0c;WHERE是一个用于指定查询条件的关键字。它允许用户根据特定的条件来筛选和查询云数据库中的数据。WHERE语句的基本语法格式是WHERE condition&#xff0c;其中condition表示查询条件&#xff0c;可以是一个或多个逻辑表达式组成的条件。 在…

第七十九天 WAF攻防-漏洞发现协议代理池GobyAWVSXray

第79天 WAF攻防-漏洞发现&协议&代理池&Goby&AWVS&Xray 知识点&#xff1a; 1、Http/s&Sock5协议 2、Awvs Xray&Goby代理 3、Pxoxifier进程代理使用 4、Safedog&BT&Aliyun防护 演示案例&#xff1a; Awws漏扫-Sadedog-白名单-内置 Awws漏…

使用Apache Kafka的Golang实践指南

您是否在寻找构建可扩展、高性能应用程序的方法&#xff0c;这些应用程序可以实时处理流数据&#xff1f;如果是的话&#xff0c;结合使用Apache Kafka和Golang是一个很好的选择。Golang的轻量级线程非常适合编写类似Kafka生产者和消费者的并发网络应用程序。它的内置并发原语&…

动态规划DP之背包问题3---多重背包问题

目录 DP分析&#xff1a; 优化&#xff1a; 二进制优化 例题&#xff1a; 01背包是每个物品只有一个&#xff0c;完全背包问题是每个物品有无限个。 那么多重背包问题就是 每个物品有有限个。 有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 si 件&#xff0c;每件体…

Mysql学习笔记之事务详解(读未提交、读以提交、可重复读、串行化读)

在这个博主的基础上&#xff0c;增加两种情况的对比&#xff1a;https://blog.csdn.net/llllllkkkkkooooo/article/details/108068919 可重复读中幻读现象&#xff08;未使用MVCC&#xff09; 设置可重复读的隔离级别 set global transaction isolation level repeatable read…

代码随想录算法训练营第day40|343. 整数拆分 、 96.不同的二叉搜索树

a.343. 整数拆分 题目链接 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: …

掼蛋的牌型与规律(上篇)

掼蛋是一项配合类的棋牌竞技游戏&#xff0c;掼蛋的最大魅力以及最集中的特点在于变化&#xff0c;在于组牌的变数。有的掼蛋新手往往先把牌配死&#xff0c;并且直接决定好出牌计划&#xff0c;然后守株待兔。掼蛋的取胜之道在于静态组合加上动态变化。本文主要介绍一下掼蛋的…

python基础篇--学习记录2

1.深浅拷贝 l1 ["张大仙","徐凤年",["李淳刚","邓太阿"]] # 变量名对应的就是内存地址,这里就是将l1的内存地址给了l2 # 现在两个变量指向同一个内存地址,l1变化l2也会变化 l2 l1 现在的需求是l2是l1的拷贝版本,但是两者是完全分割…

七彩虹@电脑cpu频率上不去问题@控制中心性能模式cpu频率上不去@代理服务器超时@账户同步设置失败

文章目录 windows电脑cpu频率上不去新电脑的系统时间问题系统时间不准造成的具体问题举例代理超时vscode同步请求失败自动校准时间 windows电脑cpu频率上不去 问题描述,标压处理器的笔记本,cpu频率上不去 如果cpu没问题的话,就应该是系统限制了功耗导致的有的笔记本有控制中心…

本鲸:打造科技招商新引擎、实现政企资源高效对接

在当今这个快速变化的时代&#xff0c;科技创新已成为推动社会进步和经济发展的核心动力。本鲸&#xff0c;作为科技创新创业服务的平台&#xff0c;正以其独特的视角和专业服务&#xff0c;为政府和企业提供一站式科技招商解决方案&#xff0c;助力构建创新驱动的经济发展新模…

b站小土堆pytorch学习记录—— P27-P29 完整的模型训练套路

文章目录 一、定义模型&#xff08;放在model.py文件中&#xff09;二、训练三、测试四、完整的训练和测试代码 一、定义模型&#xff08;放在model.py文件中&#xff09; import torch from torch import nnclass Guodong(nn.Module):def __init__(self):super(Guodong,self)…

在vue2中使用tailwindcss(完整教程)

如果你看过好多教程之后&#xff0c;还是报错&#xff0c;无法使用tailwindcss&#xff0c;我希望本教程可以让你成功上岸。 环境要求 node&#xff1a;>v14.17.0 安装tailwindcss 由于最新的tailwind css使用post css 8版本&#xff0c;vue2框架暂时还不支持&#xff0…

Springboot + Vue用户管理系统

Springboot Vue用户管理系统 主要实现了管理员的登录&#xff0c;用户管理&#xff0c;用户的增删改查等操作&#xff0c; 技术实现&#xff0c;前端采用Vue 后端采用Springboot ,前后端分离系统&#xff0c;数据库使用mysql 还用到了redis,mybatis-plus。。。。。。。。。…

10大主流压力/负载/性能测试工具推荐

在移动应用和Web服务正式发布之前&#xff0c;除了进行必要的功能测试和安全测试&#xff0c;为了保证互联网产品的服务交付质量&#xff0c;往往还需要做压力/负载/性能测试。然而很多传统企业在试水互联网的过程中&#xff0c;往往由于资源或产品迭代速度等原因忽视了这一块工…