C++修炼之路之继承<二>

目录

一:子类的六大默认成员函数 

二:继承与友元

三:继承与静态成员

四:复杂的继承关系+菱形继承+菱形虚拟继承 

1.单继承

2.多继承 

3.菱形继承;一种特殊的多继承 

4.菱形虚拟继承

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

不使用虚拟继承前数据冗余的情况

使用虚拟继承数据的情况

经典例题

五:继承和组合

接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧

衔接上篇的内容继续介绍

一:子类的六大默认成员函数 

1.默认的意思就是我们不写,编译器会自动生成一个,在子类中的默认成员函数要把父类单独看成一个独立的对象来完成对应操作

父类的默认函数

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 id):Person(name)//作为一个单独对象构造,_id(id){cout << "Student(const char* name, int id)" << endl;}Student(Student& s):Person(s)//父子类的赋值规则, _id(s._id){cout << "Student(const Student& s)" << endl;}Student& operator=(Student& s){if (this != &s){_id = s._id;Person::operator = (s);//父子类的赋值规则}cout << "Student& operator=(const Student& s)" << endl;return *this;}~Student(){//Person::~Person();cout << "~Student()" << endl;}
protected:int _id;
};

 特殊的对于子类此处的析构函数,不能显示调用父类的析构,原因为

1.由于多态的原因,析构函数统一会被处理成destructor

2.父子类的析构函数构成隐藏

3.为了保证析构安全,先子后父(如果先父后子的话,在父类析构后,在子类还可以访问父类的成员,此时就会导致访问已经释放的空间,导致越界访问),构造为先父后子

4.父类析构函数不需要显示调用,子类析构函数结束时会自动调用父类析构,保证先子后父

练习:如何实现一个不能被继承的类

方法为:可以将父类的成员函数或者整个成员访问方式设置为private,这样继承的时候无论继承方式为那种,都是不可见的

在c++11中新添加了final关键字,使用的话意味着该类不能被继承

二:继承与友元

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

如要访问子类的私有和保护成员的话,在子类中也声明友元关系(就是基类的友元声明在派生类声明一下)

三:继承与静态成员

基类中定义了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; // 学号
};Student func()
{Student st;return st;
}int main()
{Person p;Student s;func();cout << Student::_count << endl;return 0;
}

四:复杂的继承关系+菱形继承+菱形虚拟继承 

1.单继承

一个子类只有一个直接父类

2.多继承 

一个子类有两个或以上直接父类

3.菱形继承;一种特殊的多继承 

从这里就可以看出,在Assistant的对象中就有两份Person成员,这就导致数据冗余和二义性的问题,这样在访问数据的时候就不知道具体访问哪一个

4.菱形虚拟继承

于是提出了使用虚继承即添加关键字virtual来解决,这是就只有一份Person成员,只初始化一次

如:

class Person
{
public:string _name; // 姓名int _age;int _tel;// ...
};
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; // 主修课程
};void Test()
{// 这样会有二义性无法明确知道访问的是哪一个Assistant a;a.Student::_name = "小张";a.Teacher::_name = "老张";a._name = "张三";
}int main()
{Test();return 0;
}

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

不使用虚拟继承前数据冗余的情况

发现在B子类 和C子类中都有一份父类A的数据,造成数据冗余

使用虚拟继承数据的情况

 这时父类的数据只有一份,子类访问的都是同一父类的数据

这时就会看到在 添加virtual的子类中会多存储一个地址,这个地址其实存储的是距离A的偏移量

此时A同属于B和C,这样B和C该如何找到公共的A呢,这里是通过了B和C的两个指针,指向的一张表,这两个指针叫虚基表指针,这两个表叫虚基表,虚基表中存的是偏移量,通过偏移量找到A

这个偏移量就是从该位置向后跳跃的字节数,然后找到并访问父类的成员数据 

经典例题

 

对于p1和p3指向的位置相同,但访问权限不同 

打印顺序为什么?

对于任何的派生类的构造都要 调用基类的构造

注意:初始化列表出现的顺序是按声明顺序来执行的,不是执行顺序

所以结果为 class A,class B ,class C,class D

一般不建议设计出菱形继承

五:继承和组合

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

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

对于这两个的大小都是一样大的, 

但对于继承父类中的protected 成员可以在子类中访问

对于组合的话,一个类中的protected成员,另一个类不能使用,不能直接调用另一个类的public成员函数

3.

4.实际尽量多去使用组合,组合的耦合度低,代码的可维护性好。对于有些关系就适合继承就使用继承,对于多态,也必须实现继承,对于既能用组合又能继承的,就使用组合 

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

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

相关文章

华为OD-C卷-内存冷热标记[100分]C++-100%

题目描述 现代计算机系统中通常存在多级的存储设备,针对海量 workload 的优化的一种思路是将热点内存页优先放到快速存储层级,这就需要对内存页进行冷热标记。 一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,则认为是热内存页,…

小程序 前端如何用wx.request获取 access_token接口调用凭据

在微信小程序中,获取access_token通常是通过wx.request方法来实现的。以下是一个简单的示例代码: 1.获取小程序的appID 与 secret(小程序密钥) 登录之后,请点击左侧的"开发管理"==>点击"开发设置" 就可以找到 2. 在javascript 中的代码: // 定…

【大模型完全入门手册】——大模型入门理论(基于Transformer的预训练语言模型)

博主作为一名大模型开发算法工程师,很希望能够将所学到的以及实践中感悟到的内容梳理成为书籍。作为先导,以专栏的形式先整理内容,后续进行不断更新完善。希望能够构建起从理论到实践的全流程体系。 助力更多的人了解大模型,接触大模型,一起感受AI的魅力! Transformer架构…

性能优化工具

CPU 优化的各类工具 network netperf 服务端&#xff1a; $ netserver Starting netserver with host IN(6)ADDR_ANY port 12865 and family AF_UNSPEC$ cat netperf.sh #!/bin/bash count$1 for ((i1;i<count;i)) doecho "Instance:$i-------"# 下方命令可以…

Rust 语言使用 SQLite 数据库

SQLite 是一种广泛使用的轻量级数据库&#xff0c;它通过简单的文件来承载数据&#xff0c;无需复杂的服务器配置。正因如此&#xff0c;它成为了许多桌面和移动应用的首选数据库。在 Rust 生态中&#xff0c;rusqlite 库为开发者提供了操作 SQLite 数据库的简洁且有效的方法。…

如何用Redis高效实现12306的复杂售票业务

12306的售票业务是一个复杂的系统&#xff0c;需要考虑高并发、高可用、数据一致性等问题。使用Redis作为缓存和持久化存储&#xff0c;可以提高系统的性能和可扩展性&#xff0c;以下是一些可能的实现方式&#xff1a; 1 票源信息缓存&#xff1a;将票源信息&#xff08;如车次…

算法刷题记录2

4.图 4.1.被围绕的区域 思路&#xff1a;图中只有与边界上联通的O才不算是被X包围。因此本题就是从边界上的O开始递归&#xff0c;找与边界O联通的O&#xff0c;并标记为#&#xff08;代表已遍历&#xff09;&#xff0c;最后图中剩下的O就是&#xff1a;被X包围的O。图中所有…

SQC、SQA

QC 品质控制/质量控制&#xff08;QC即英文Quality Control的简称&#xff0c;中文意义是品质控制&#xff09;其在ISO8402&#xff1a;1994的定义是“为达到品质要求所采取的作业技术和活动”。有些推行ISO9000的组织会设置这样一个部门或岗位&#xff0c;负责ISO9000标准所要…

Spring Boot 中 Controller 接口参数注解全攻略与实战案例详解

引言 在 Spring Boot 应用程序中&#xff0c;Controller 是 MVC 架构模式中的核心组件之一&#xff0c;负责处理 HTTP 请求并返回响应结果。为了更好地映射请求、解析请求参数、执行业务逻辑和生成视图或 JSON 数据&#xff0c;Controller 中广泛使用了各种注解。本文将全面梳…

温湿度传感器(DHT11)以及光照强度传感器(BH1750)的使用

前言 对于一些单片机类的环境检测或者智能家居小项目中&#xff0c;温湿度传感器&#xff08;DHT11&#xff09;以及光照强度传感器&#xff08;BH1750&#xff09;往往是必不可少的两个外设&#xff0c;下面我们来剖析这两个外设的原理&#xff0c;以及使用。 1. 温湿度传感…

C语言中,__attribute__关键字

在C语言中&#xff0c;__attribute__是一种特殊的关键字&#xff0c;用于提供关于变量、函数或类型的附加信息。这些信息可以用于编译器优化、代码检查或其他目的。 以下是一些常见的C语言attribute及其用法&#xff1a; 1. __attribute__((const))&#xff1a;表示一个变量的…

Prometheus指标

文章目录 Prometheus指标主要参数解释一、可用性监测(0代表存在异常或未启动,1代表运行中)二、节点监测三、服务监测1.HDFS监测2.Yarn监测3.Hive监测4.Kafka监测5.Zookeeper监测Prometheus指标 主要参数解释 # 节点IP和端口(instance) 例如:192.168.1.226:9100、192.168.1.…

java篇-Springboot解决跨域问题的三种方式

第一种&#xff1a;添加CrossOrigin注解 在Controller层对应的方法上添加CrossOrigin或者类上添加CrossOrigin package com.example.controller;import com.example.model.Book; import com.example.service.InBookService; import org.springframework.beans.factory.anno…

软件工程的生命周期

软件工程的生命周期 1.市场调研用户的需求&#xff0c;并进行可行性分析&#xff08;从多个角度分析能否达到预期收益&#xff09;。 2.立项&#xff1a;确定项目组核心骨干成员&#xff0c;以及各阶段的里程碑。 3.需求调研&#xff1a;产品经理深度挖掘用户需求&#xff0c;将…

简明 Python 教程(第14章 Python的多线程)

Python多线程是指在Python程序中可以同时运行多个线程&#xff0c;每个线程可以执行不同的任务。Python提供了两个标准库来支持多线程&#xff1a;threading和_thread。通常&#xff0c;推荐使用threading模块&#xff0c;因为它提供了更高级别的API&#xff0c;更易于使用。 …

嵌入式4-18

做一个简单数据库终端操作系统 #include <myhead.h> int main(int argc, const char *argv[]) {int id;char name[16];float score;sqlite3 *pNULL;if(sqlite3_open("./my.db",&p)!SQLITE_OK){printf("sqlite3_open error\n");return -1;} …

python中中英文打印对齐解决方案

在python中&#xff0c;有时候会出现中英文混合输出的情形&#xff0c;但是由于中文默认是全角格式&#xff08;一个中文字符占用两个字符宽度&#xff09;&#xff0c;这会对python原生的print函数带来一些障碍。尤其是用户用print对齐输出的时候&#xff0c;这种差异会导致文…

顺序表链表经典算法题

1.链表反转 typedef struct ListNode listnode; struct ListNode* reverseList(struct ListNode* head) {if(head NULL){return head;}listnode* p1 NULL;listnode* p2 head;listnode* p3 head->next;while(p2){p2->next p1;p1 p2;p2 p3;if(p3)p3 p3->next;}…

ASP.NET MVC企业级程序设计 (商品管理:小计,总计,删除,排序)

目录 效果图 实现过程 1创建数据库 2创建项目文件 3创建控制器&#xff0c;右键添加&#xff0c;控制器 ​编辑 注意这里要写Home​编辑 创建成功 数据模型创建过程之前作品有具体过程​编辑 4创建DAL 5创建BLL 6创建视图&#xff0c;右键添加视图 ​编辑 7HomeCont…

ST-GCN模型详解(+openpose)

ST-GCN模型详解&#xff08;openpose&#xff09; 一、什么是ST-GCN呢 基于骨架的动作识别&#xff08;Skeleton-Based Action Recognition&#xff09;主要任务是从一系列时间连续的骨骼关键点&#xff08;2D/3D&#xff09;中识别出正在执行的动作。因为牵涉到骨骼框架这种…