【C++】继承,菱形继承,虚拟继承,组合详解

目录

1. 继承概念与定义

1.1 概念

1.2 定义

2. 父类与子类的赋值规则

3. 继承的作用域

4. 子类的默认成员函数

5. 继承与友元

6. 继承与静态成员

7. 菱形继承

7.1 继承关系

7.2 菱形继承的问题

7.3 虚拟继承

8. 继承与组合


1. 继承概念与定义

1.1 概念

1. 继承:保持原有类特性的基础上进行扩展,增加功能,这样产生新的类(派生类),本质是类的复用。

2. 子类会继承父类的成员变量和成员函数。

class Person
{
public:void Print(){...}protected:string _name = "peter"; // 姓名int _age = 18;  // 年龄
};class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}

1.2 定义

【格式】

【继承方式】

1. 有三种继承方式。

【继承后成员访问限定符的变化】

1. 父类私有成员继承后子类不可见不可用,无论子类类内类外。

2. 父类公有或保护成员继承后与继承方式比较,谁小就是谁,public > protected > private。

3. 父类的保护成员,类外不能访问,但是可以继承给子类类内访问。

 

2. 父类与子类的赋值规则

1. 子类可以赋值给父类/父类指针/父类引用。

2. 父类不可以赋值给子类。

3. public继承中,子类可以看作是一个特殊的父类,is-a的关系。

class Person
{
protected :string _name; // 姓名string _sex;  // 性别int _age; // 年龄
};class Student : public Person
{
public :int _No ; // 学号
};void Test ()
{Student s;Person p = s;Person* pp = &s; //指向子类的父类部分Person& rp = s; //父类部分的引用
}

 

3. 继承的作用域

1. 父类和子类都有自己的独立作用域。

2. 父类和子类允许有同名成员,默认访问子类的,因为隐藏了父类的同名成员,想访问父类的同名成员使用基类::基类成员显示访问。

class Person
{
protected :int _num = 111;   
};class Student : public Person
{
public:void Print(){cout << Person::_num << endl; //显示访问父类cout << _num << endl; //默认访问子类同名}protected:int _num = 999; 
};

【注意】

1. 重载必须是相同作用域。

2. 成员函数的函数名相同就会构成隐藏。

class A
{
public:void fun(){cout << "func()" << endl;}
};class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" <<i<<endl;}
};

 

4. 子类的默认成员函数

1. 我们把子类的成员变量看作三部分,内置类型,自定义类型,继承的父类成员变量,把继承的父类看作一个整体。

2. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,子类变量的构造自己实现。

3. 子类的拷贝构造同理,派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,自己实现子类的拷贝构造。

4. 派生类的operator=必须要调用基类的operator=完成基类的复制。

5. 子类的析构函数结束后会自动调用父类的析构函数,析构的顺序是先子后父,因为先父后子的子可能会访问父。

//父类
class Person
{
public://父类构造Person(const char* name = "peter"): _name(name){cout<<"Person()" <<endl;}//父类拷贝构造  Person(const Person& p): _name(p._name){cout<<"Person(const Person& p)" <<endl;}//父类赋值重载Person& operator=(const Person& p ){cout<<"Person operator=(const Person& p)"<< endl;if (this != &p)_name = p ._name;return *this ;}//父类析构    ~Person(){cout<<"~Person()" <<endl;}protected:string _name; // 姓名
};//子类
class Student : public Person
{
public://子类构造Student(const char* name, int num):Person(name) //父类部分的构造交给父类构造,_num(num){cout<<"Student()" <<endl;}//子类拷贝Student(const Student& s):Person(s) //父类部分的拷贝交给父类拷贝,_num(s._num){cout<<"Student(const Student& s)" <<endl ;}//子类赋值重载   Student& operator=(const Student& s){cout<<"Student& operator= (const Student& s)"<< endl;if (this != &s){Person::operator=(s); //这里显示调用因为构成了隐藏_num = s._num;}return *this ;} //子类析构   ~Student() {cout<<"~Student()" <<endl;}protected:int _num ; //学号
};

 

5. 继承与友元

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

 

6. 继承与静态成员

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

2. 父类的静态成员不属于某个对象,属于整个类,继承的子类也有使用权。

 

7. 菱形继承

7.1 继承关系

【单继承】

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

【多继承】

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

【菱形继承】

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

7.2 菱形继承的问题

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

在Assistant的对象中Person成员会有两份。

1. 两个_name会造成数据二义性,这个可以显示调用解决。

2. 数据冗余无法解决。

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 ; // 主修课程
};

7.3 虚拟继承

1. 虚拟继承可以解决菱形继承的二义性和数据冗余的问题。

2. vircual关键字要加在继承冗余的类的位置,比如这里冗余的是person类,那么谁继承person就要用虚拟继承。

class Person
{
public :string _name ; // 姓名
};class Student : virtual public Person
{
protected :int _num ; //学号
};class Teacher : virtual public Person
{
protected :int _id ; // 职工编号
};class Assistant : public Student, public Teacher
{
protected :string _majorCourse ; // 主修课程
};

【原理】

1. 冗余的变量会被放到最下面。

2. 原本的位置变成一个地址,这个地址指向一张表(虚基表),表里有这个冗余变量的偏移量,通过偏移量可以找到它。

8. 继承与组合

1. public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。

2. 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。

3. 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。在继承方式中,基类的内部细节对子类可见。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。

4. 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复(black-box reuse),因为对象的内部细节是不可见的。组合类之间没有很强的依赖关系,耦合度低。

//组合
class A
{
public:int _a;
}class B 
{
private:A a;
}

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

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

相关文章

论文速递 | Management Science 8月文章合集

编者按 在本系列文章中&#xff0c;我们对顶刊《Management Science》于8月份发布文章中进行了精选&#xff08;共9篇&#xff09;&#xff0c;并总结其基本信息&#xff0c;旨在帮助读者快速洞察行业最新动态。 推荐文章1 ● 题目&#xff1a;Optimal Mechanism Design with …

红队信息搜集扫描使用

红队信息搜集扫描使用 红队行动中需要工具化一些常用攻击&#xff0c;所以学习一下 nmap 等的常规使用&#xff0c;提供灵感 nmap 帮助 nmap --help主机扫描 Scan and no port scan&#xff08;扫描但不端口扫描&#xff09;。-sn 在老版本中是 -sP&#xff0c;P的含义是 P…

基于SPI协议的Flash驱动控制

1、理论知识 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围设备接口&#xff09;通讯协议&#xff0c;是Motorola公司提出的一种同步串行接口技术&#xff0c;是一种高速、全双工、同步通信总线&#xff0c;在芯片中只占用四根管脚用来控制及数据传输&#…

【Python】利用Python+thinker实现旋转转盘

需求/目的&#xff1a;用Pythonthinker实现转盘&#xff0c;并且能够随机旋转任意角度。 转盘形式&#xff1a; 主界面&#xff1a; from tkinter import *winTk() win.title("大转盘") win.geometry("300x400")win.mainloop() 转盘绘制&#xff1a; 这…

USMART调试组件学习

USMART调试组件学习日记 写于2024/9/24日晚 文章目录 USMART调试组件学习日记1. 简介2. 调试组件组成3.程序流程图4. 移植解析5. 实验效果5. 实验效果 1. 简介 USMART 是由正点原子开发的一个灵巧的串口调试互交组件&#xff0c;通过它你可以通过串口助手调用程序里面的任何函…

SigLIP技术小结

paperhttps://arxiv.org/abs/2303.15343githubhttps://github.com/google-research/big_vision个人博客位置http://myhz0606.com/article/siglip 1 背景 CLIP[1]自提出以来在zero-shot分类、跨模态搜索、多模态对齐等多个领域得到广泛应用。得益于其令人惊叹的能力&#xff0…

备考中考的制胜法宝 —— 全国历年中考真题试卷大全

在中考这场重要的战役中&#xff0c;每一分都至关重要。为了帮助广大考生更好地备考&#xff0c;我们精心整理了这份全国历年中考真题试卷大全&#xff0c;旨在为大家提供最全面、最权威的备考资料。 文章目录 1. 全科覆盖&#xff0c;无遗漏2. 历年真题&#xff0c;权威可靠3.…

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构&#xff08;这会导致我们查询的时间复杂度变为O(n)&#xff09;&#xff0c;然而AVL树就很好的解决了这一问题&#xff08;归功于四种旋转的方法&#xff09;&#xff0c;它让我们的树的查询的时间复杂度变得接近…

QT--基础

将默认提供的程序都注释上意义 0101.pro QT core gui #QT表示要引入的类库 core&#xff1a;核心库 gui&#xff1a;图形化界面库 #如果要使用其他库类中的相关函数&#xff0c;则需要加对应的库类后&#xff0c;才能使用 greaterThan(QT_MAJOR_VERSION, 4): QT wid…

关于frp Web界面-----frp Server Dashboard 和 frp Client Admin UI

Web 界面 官方文档&#xff1a;https://gofrp.org/zh-cn/docs/features/common/ui/ 目前 frpc 和 frps 分别内置了相应的 Web 界面方便用户使用。 客户端 Admin UI 服务端 Dashboard 服务端 Dashboard 服务端 Dashboard 使用户可以通过浏览器查看 frp 的状态以及代理统计信…

GD32片内flash读写数据

如有技术问题及技术需求请加作者微信! GD32片内Flash的读写数据是微控制器编程中的常见任务,主要用于存储程序代码、配置参数或用户数据等。以下将详细介绍GD32片内Flash的读写数据方法和程序。 一、GD32 Flash的基本特性 存储空间划分:GD32的Flash存储空间通常分为主存储块…

罕见 P0 故障!上交所崩了 ~

大家好啊&#xff0c;我是董董灿。 昨天&#xff08;9月27号&#xff09;很多朋友可能都刷到一个消息&#xff1a;上交所崩了。 原因是在近期经济政策的刺激下&#xff0c;我大A股市场出现反弹&#xff0c;很多投资者纷纷涌入大A进行交易。 A 股反弹本来是件好事&#xff0c…

常见网络服务搭建之SSH服务搭建

SSH为Secure Shell的缩写&#xff0c;由IETF的网络小组&#xff08;Network Working Group&#xff09;所制定的建立在应用层基础上的安全协议。SSH是较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;利用SSH协议可以有效防止远程管理过程中的信…

计算机毕业设计 招生宣传管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

代码随想录算法训练营第十七天|654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

654.最大二叉树 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二…

番外篇 | 复现AC-YOLOv5,进行自动化织物缺陷检测

前言:Hello大家好,我是小哥谈。我们提出了一种基于AC-YOLOv5的新型纺织缺陷检测方法。将空洞空间金字塔池化(ASPP)模块引入YOLOv5主干网络中,提出了squeeze-and-excitation(CSE)通道注意力模块,并将其引入到YOLOv5主干网络中。🌈 目录 🚀1.基础概念 🚀2.添…

Chrome浏览器如何修改语言(修改成英文、中文)

一、背景 有的时候需要修改chrome浏览器的语言&#xff0c;比如如下是中文&#xff0c;我要修改成英文 二、下面的方法已经无效了 在语言里添加"英语"并且置顶&#xff0c;试了很久&#xff0c;设置完后重启浏览器什么的&#xff0c;都无法改成英文。 这个可能…

ECMAScript 与 JavaScript 的区别详解

ECMAScript 与 JavaScript 的区别详解 在前端开发的学习过程中&#xff0c;很多开发者会遇到两个常见的术语&#xff1a;ECMAScript 和 JavaScript。这两个术语常常被混淆&#xff0c;因为它们密切相关&#xff0c;甚至有时被认为是同一件事。本文将详细解析 ECMAScript 和 Ja…

青动CRM V3.2.1

全面解决企业销售团队的全流程客户服务难题旨在助力企业销售全流程精细化、数字化管理&#xff0c;全面解决企业销售团队的全流程客户服务难题&#xff0c;帮助企业有效盘活客户资源、量化销售行为&#xff0c;合理配置资源、建立科学销售体系&#xff0c;提升销售业绩。标准授…

【面试题】软件测试实习(含答案)

软件测试实习常见面试题&#xff0c;主要是功能测试相关的基础问题 目录 一、软件测试基础 1、介绍一下你最近的项目&#xff0c;以及工作职责 2、软件项目的测试流程? 3、黑盒测试与白盒测试的区别? 4、黑盒测试常见的设计方法?怎么理解等价类方法和边界值方法 1&…