当前位置: 首页 > news >正文

【C++ 学习 ⑰】- 继承(下)

目录

一、派生类的默认成员函数

二、继承与友元

三、继承与静态成员

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

五、继承和组合


 

 


一、派生类的默认成员函数

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数,那么必须在派生类的构造函数的初始化列表中显示调用基类的构造函数。

  2. 派生类的拷贝构造函数必须调用基类的拷贝构造函数完成基类的那一部分成员的拷贝初始化。

  3. 派生类的 operator= 必须调用基类的 operator= 完成基类的那一部分成员的赋值。

  4. 派生类的析构函数在被调用完后,会自动调用基类的析构函数清理基类的那一部分成员,即在派生类的析构函数中不用显示地调用基类的析构函数。

  5. 在创建派生类对象时,先调用基类的构造函数,再调用派生类的构造函数。

  6. 在销毁派生类对象时,先调用派生类的析构函数,再调用基类的析构函数。

#include <iostream>
using namespace std;
​
class Person
{
public:Person(const char* name = "张三", int age = 18): _name(name), _age(age){cout << "Person::default constructor" << endl;}
​Person(const Person& p): _name(p._name), _age(p._age){cout << "Person(const Person& p)" << endl;}
​Person& operator=(const Person& p){cout << "Person& operator=(const Person p)" << endl;if (this != &p){_name = p._name;_age = p._age;}return *this;}
​~Person(){cout << "~Person()" << endl;}
protected:string _name;  // 姓名int _age;  // 年龄
};
​
class Student : public Person
{
public:Student(const char* name = "张三", int age = 18, int stu_id = 0): Person(name, age), _stu_id(stu_id){cout << "Student::default constructor" << endl;}
​Student(const Student& s): Person(s), _stu_id(s._stu_id){cout << "Student(const Student& s)" << endl;}
​Student& operator=(const Student& s){cout << "Student& operator=(const Student& s)" << endl;if (this != &s){Person::operator=(s);  // operator=(s); 会陷入死循环_stu_id = s._stu_id;}return *this;}
​~Student(){cout << "~Student()" << endl;}
protected:int _stu_id;  // 学号
};
​
int main()
{Student s1("李四", 20, 1);// Person::default constructor// Student::default constructor
​Student s2(s1);// Person(const Person& p)// Student(const Student & s)
​Student s3;// Person::default constructor// Student::default constructor
​s3 = s1;// Student& operator=(const Student& s)// Person& operator=(const Person p)
​// ~Student()// ~Person()// ~Student()// ~Person()// ~Student()// ~Person()return 0;
}

 

 


二、继承与友元

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

#include <iostream>
using namespace std;
​
class Student;
class Person
{friend void Print(const Person& p, const Student& s);
protected:string _name = "张三";int _age = 18;
};
​
class Student : public Person
{// 必须声明,否则会报错friend void Print(const Person& p, const Student& s);  
protected:int _stu_id = 0;
};
​
void Print(const Person& p, const Student& s)
{cout << p._name << " " << p._age << endl;cout << s._stu_id << endl;
}
​
int main()
{Person p;Student s;Print(p, s);return 0;
}

 

 


三、继承与静态成员

如果基类定义了 static 静态成员,无论派生出了多少个类,在整个继承体系中都只有一个 static 静态成员实例

#include <iostream>
using namespace std;
​
class Person
{
public:Person() { ++_count; }
protected:string _name;int _age;
public:static int _count;  // static 静态成员变量
};
​
int Person::_count = 0;
​
class Student : public Person
{
protected:int _stu_id;
};
​
class Graduate : public Student
{
protected:string _seminarCourse;  // 研究科目
};
​
int main()
{cout << &Person::_count << " " << &Student::_count<< " " << &Graduate::_count << endl;// 输出的三个地址相同Person p1;Student s1;Student s2;Graduate g1;Graduate g2;Graduate g3;cout << Person::_count << endl;  // 6return 0;
}

 

 


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

单继承:一个派生类只有一个直接基类时,称这种继承关系为单继承。

多继承:一个派生类有两个或两个以上直接基类时,称这种继承关系为多继承。

菱形继承是多继承的一种特殊情况,它会造成数据冗余和二义性的问题,例如

#include <iostream>
using namespace std;
​
// 间接基类 A
class A
{
public:int _a;
};
​
// 直接基类 B
class B : public A
{
public:int _b;
};
​
// 直接基类 C
class C : public A
{
public:int _c;
};
​
// 派生类 D
class D : public B, public C
{
public:int _d;
};
​
int main()
{D d;// 为了消除歧义,必须在 _a 前面指明它具体来自哪个类d.B::_a = 0;d.C::_a = 1;d._b = 2;d._c = 3;d._d = 4;return 0;
}

f0745668420b4395a7ba770acb62a36c.png

 

为了解决菱形继承中的问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员

在继承方式前面加上 virtual 关键字就是虚继承,例如

#include <iostream>
using namespace std;
​
// 间接基类 A
class A
{
public:int _a;
};
​
// 直接基类 B
class B : virtual public A  // 虚继承
{
public:int _b;
};
​
// 直接基类 C
class C : virtual public A  // 虚继承
{
public:int _c;
};
​
// 派生类 D
class D : public B, public C
{
public:int _d;
};
​
int main()
{D d;d._a = 1;  // okd._b = 2;d._c = 3;d._d = 4;return 0;
}

5d814df4b34a4815b1592c104b9111da.png

 

虚继承底层实现原理与编译器相关,一般是通过虚基类指针和虚基类表实现的

每个虚继承的子类都有一个虚基类指针,该指针指向一个虚基类表,表中记录了虚基类和本类的偏移量,通过这个偏移量就可以找到虚基类成员

当虚继承的子类被当作父类继承时,虚基类指针也会被继承

 

 


五、继承和组合

面向对象系统中功能复用的两种最常用技术是类继承对象组合(object composition)

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

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

因此在实际中,尽量多使用组合。不过继承也有用武之地的:public 继承是一种 is-a 的关系,即每个派生类对象都是一个基类对象,组合是一种 has-a 的关系,即假设 B 组合了 A,那么每个 B 类对象都有一个 A 类对象,而有些关系就适合用继承;另外要实现多态,也必须要用继承

例一

class Car
{
protected:string _color;  // 颜色string _num;  // 车牌号
};
​
class AITO : public Car
{
public:void Describe() const { cout << "Intelligent" << endl; }
};
​
class AVATR : public Car
{
public:void Describe() const { cout << "luxurious" << endl; }
};

AITO、AVATR 和 Car 构成 is-a 的关系

例二

class Tire
{
protected:string _brand;  // 品牌size_t _size;  // 尺寸
};
​
class Car
{
protected:string _color;string _num;Tire _t;
};

Car 和 Tire 构成 has-a 的关系

 

相关文章:

【C++ 学习 ⑰】- 继承(下)

目录 一、派生类的默认成员函数 二、继承与友元 三、继承与静态成员 四、复杂的菱形继承及菱形虚拟继承 五、继承和组合 一、派生类的默认成员函数 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数&#xff0c;那么必须在派生…...

kafka学习笔记

1、kafka是什么&#xff1f; kafka是一个高吞吐&#xff0c;分布式&#xff0c;基于发布/订阅的消息系统&#xff0c;最大的特性就是可以实时的处理大量的数据以满足各种需求场景&#xff1a;日志收集&#xff0c;离线和在线的消息消费&#xff0c;等等 2、kakfa的基础架构&am…...

阀门状态监测和预测性维护的原理和实施步骤

随着制造业数字化转型的推进&#xff0c;预测性维护&#xff08;Predictive Maintenance&#xff0c;简称PdM&#xff09;成为提高生产效率和设备可靠性的关键策略之一。在流程工厂中&#xff0c;阀门作为重要的设备之一&#xff0c;起着控制流体流动的关键作用。本文将探讨如何…...

复习之web服务器--apache

PS&#xff1a;Vim复制小技巧 一、实验环境 两台虚拟机 (nodea,nodeb)配置ip搭建软件仓库关闭selinux [rootftp Desktop]# hostnamectl set-hostname nodea.westos.org [rootftp Desktop]# hostname nodea.westos.org [rootftp Desktop]# ifconfig enp1s0: flags4163<UP,B…...

[Unity] 单例设计模式, 可供继承的单例组件模板类

一个可供继承的单例组件模板类: public class SingletonComponent<TComponent> : Componentwhere TComponent : SingletonComponent<TComponent> {static TComponent _instance;private static TComponent GetOrFindOrCreateComponent(){// 双检索if (_instance …...

Linux知识点 -- Linux多线程(三)

Linux知识点 – Linux多线程&#xff08;三&#xff09; 文章目录 Linux知识点 -- Linux多线程&#xff08;三&#xff09;一、线程同步1.概念理解2.条件变量3.使用条件变量进行线程同步 二、生产者消费者模型1.概念2.基于BlockingQueue的生产者消费者模型3.单生产者单消费者模…...

android java 硬编码保存mp4 jni数据转换

目录 java imagereader编码保存 java NV21toYUV420SemiPlanar 编码保存视频用&#xff1a; imageReader获取nv21 jni NV12toYUV420SemiPlanar函数&#xff1a; 代码来自博客&#xff1a; 【Android Camera2】彻底弄清图像数据YUV420_888转NV21问题/良心教学/避坑必读!_yuv…...

那些你不得不知道的HTML知识点

目录 1、行内元素有哪些&#xff1f;块级元素有哪些&#xff1f; 空(void)元素有哪些&#xff1f;2、页面导入样式时&#xff0c;使用link和import有什么区别&#xff1f;3、title与h1的区别、b与strong的区别、i与em的区别&#xff1f;3.1 title与h1的区别&#xff1a;3.2 b与…...

如何复制主播的性格(此乃广告文)

上面这份ppt写于Fay开源之前。当然&#xff0c;以现在的认知再去评价当时的设计&#xff0c;会发现有诸多的不严谨&#xff0c;甚至缺憾。比如&#xff0c;以单层的网络结构肯定无法拟合人性这个复杂的东西&#xff0c;人性也不是只受已知的几个参数所作用。但我现在想说的是&a…...

【ES6】—【新特性】—Symbol详情

一、一种新的原始数据类型 定义&#xff1a;独一无二的字符串 二、 声明方式 1. 无描述声明 let s1 Symbol() let s2 Symbol() console.log(s1, s2) // Symbol() Symbol() console.log(s1 s2) // falsePS: Symbol 声明的值是独一无二的 2. 有描述的声明 let s1 Symb…...

openresty安装与网站发布

文章目录 安装依赖下载安装包解压安装包安装启动nginx配置环境变量配置开机启动发布静态网站 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台&#xff0c;其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动…...

创建延时队列、springboot配置多个rabbitmq

创建延时队列 queue.file_delay_destroy x-dead-letter-exchange: exchange.file_delay_destroy x-message-ttl: 259200000 259200000为3天,1000为1秒创建普通队列 queue.file_destroy创建普通交换机 exchange.file_delay_destroytype选择fanout 交换机绑定普通队列 (图中…...

在kaggle中用GPU使用CGAN生成指定mnist手写数字

文章目录 1项目介绍2参考文章3代码的实现过程及对代码的详细解析独热编码定义生成器定义判别器打印我们的引导信息模型训练迭代过程中生成的图片损失函数的变化 4总结5 模型相关的文件 1项目介绍 在GAN的基础上进行有条件的引导生成图片cgan 2参考文章 GAN实战之Pytorch 使用…...

【NI USRP】哪些 USRP 设备支持全双工,哪些支持半双工?

译者 东枫电子科技 设备构成 NI USRPEttus USRPUSRP-2900B200USRP-2901B210USRP-2920N210 WBXUSRP-2921N210 XCVR 2450USRP-2922N210 SBXUSRP-2930N210 WBX GPSDOUSRP-2932N210 SBX GPSDOUSRP-2940RX310 WBX (x2)USRP-2942RX310 SBX (x2)USRP-2943RX310 CBX (x2)U…...

不拼花哨,只拼实用:unittest指南,干货为王!

Python为开发者提供了内置的单元测试框架 unittest&#xff0c;它是一种强大的工具&#xff0c;能够有效地编写和执行单元测试。unittest 提供了完整的测试结构&#xff0c;支持自动化测试的执行&#xff0c;能够对测试用例进行组织&#xff0c;并且提供了丰富的断言方法。最终…...

mysql 获取json数组中某个字段根据下标

MySQL获取JSON数组中某个字段根据下标 在MySQL中&#xff0c;JSON数据类型可以方便地存储、操作和查询包含复杂结构的数据。当我们需要从JSON数组中获取某个字段时&#xff0c;可以使用MySQL的JSON函数来实现。 1. JSON数据类型简介 JSON&#xff08;JavaScript Object Nota…...

深入理解Redis缓存穿透、击穿、雪崩及解决方案

深入理解Redis缓存穿透、击穿、雪崩及解决方案 一、简介Redis 简介缓存作用与优化 二、缓存问题的分类缓存穿透缓存击穿缓存雪崩 三、缓存穿透的解决方案布隆过滤器缓存空对象接口层校验 四、缓存击穿的解决方案互斥锁热点数据提前加载 五、缓存雪崩的解决方案增加缓存容错能力…...

java八股文面试[java基础]——字节码

字节码技术应用 字节码技术的应用场景包括但不限于AOP&#xff0c;动态生成代码&#xff0c;接下来讲一下字节码技术相关的第三方类库&#xff0c;第三方框架的讲解是为了帮助大家了解字节码技术的应用方向&#xff0c;文档并没有对框架机制进行详细分析&#xff0c;有兴趣的可…...

新能源汽车技术的最新进展和未来趋势

文章目录 电池技术的进步智能驾驶与自动驾驶技术充电基础设施建设新能源汽车共享和智能交通未来趋势展望结论 &#x1f389;欢迎来到AIGC人工智能专栏~探索新能源汽车技术的最新进展和未来趋势 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客…...

知虾shopee数据分析工具:shopee出单的商机利器

当今数字化时代&#xff0c;数据已经成为商业成功的关键要素之一。而Shopee作为东南亚最大的电商平台之一&#xff0c;其强大的数据分析工具正为商家提供了宝贵的市场洞察和决策支持。本文将深入探讨Shopee数据分析工具如何帮助商家抓住商机并取得成功。 洞察消费者需求&#x…...

屏幕取色与设计辅助工具 ColorWanted:提升设计师与开发者工作效率的专业解决方案

屏幕取色与设计辅助工具 ColorWanted&#xff1a;提升设计师与开发者工作效率的专业解决方案 【免费下载链接】ColorWanted Screen color picker for Windows (Windows 上的屏幕取色器) 项目地址: https://gitcode.com/gh_mirrors/co/ColorWanted 你是否曾遇到这样的工作…...

从“看见光点”到“看懂世界”:视觉重建让这个世界变得更近一些

三十多年前&#xff0c;“让盲人重新看见”更像一句带有未来感的科学想象。而今天&#xff0c;这件事已经进入临床试验和真实的人体研究。视觉重建之所以被视为脑机接口里最具挑战性的方向之一&#xff0c;不只是因为它要解决“能不能刺激大脑”的问题&#xff0c;更因为它要回…...

深入解析单片机通信协议:1-Wire与UART的实战应用

1. 1-Wire协议&#xff1a;从DHT11温湿度传感器说起 第一次接触1-Wire协议是在一个智能农业项目中&#xff0c;当时需要低成本监测大棚温湿度。DHT11这个20块钱的小模块让我印象深刻——只需要一根数据线就能同时传输温度和湿度数据。这种单线通信的神奇之处在于&#xff0c;它…...

双向充放电前馈控制:储能变流器PCS_PWM变流器的SVPWM调制与实现

【复现】储能变流器PCS_PWM变流器双向充放电前馈控制SVPWM调制 1、电路构成&#xff1a;三相电网、三相 PWM变流器、Buck/Boost 变换器和蓄电池 2、三相变流器控制&#xff1a;采用电压外环、电流内环双闭环PI 控制&#xff0c;电网电压和电容电流前馈&#xff0c;电感电流解耦…...

AI集成开发工程师的技术实践与转型之路

第一章:技术架构演进与AI融合趋势 1.1 传统开发范式的演进 现代软件开发正经历从单一业务系统向智能化业务系统的转型。传统的.NET技术栈作为企业级应用开发的基石,其技术架构也在不断演进: // 典型的三层架构示例 public class BusinessLogic {private readonly IDataAc…...

GLM-4v-9b效果展示:直播带货截图→话术分析+转化点提炼

GLM-4v-9b效果展示&#xff1a;直播带货截图→话术分析转化点提炼 1. 模型能力概览 GLM-4v-9b是智谱AI在2024年开源的多模态视觉-语言模型&#xff0c;拥有90亿参数。这个模型最大的特点是能够同时理解图片和文字&#xff0c;支持中英文多轮对话&#xff0c;在11201120高分辨…...

5分钟学会使用OrigamiSimulator:实时WebGL折纸模拟器完全指南

5分钟学会使用OrigamiSimulator&#xff1a;实时WebGL折纸模拟器完全指南 【免费下载链接】OrigamiSimulator Realtime WebGL origami simulator 项目地址: https://gitcode.com/gh_mirrors/or/OrigamiSimulator OrigamiSimulator是一款基于WebGL的实时折纸模拟器&#…...

Omni-Vision Sanctuary 网络协议分析辅助:可视化网络数据包与流量模式识别

Omni-Vision Sanctuary 网络协议分析辅助&#xff1a;可视化网络数据包与流量模式识别 1. 网络数据可视化的新思路 网络工程师每天面对海量的数据包和流量日志&#xff0c;传统的分析工具往往需要依赖复杂的命令行操作和专业图表解读。而Omni-Vision Sanctuary模型为我们提供…...

PasteMD效果展示:3秒将ChatGPT对话转换为规范技术报告

PasteMD效果展示&#xff1a;3秒将ChatGPT对话转换为规范技术报告 1. 为什么你需要这个工具 你有没有过这样的经历&#xff1a;在ChatGPT里反复调试出一段完美的技术方案&#xff0c;复制粘贴到Word文档时却变成一团乱码&#xff1f;公式显示成一串LaTeX代码&#xff0c;表格错…...

VLM | 从视觉语言模型到自动驾驶决策的“慢思考”系统

1. 视觉语言模型&#xff08;VLM&#xff09;的本质与突破 当我们谈论自动驾驶时&#xff0c;大多数人首先想到的是激光雷达、摄像头和复杂的算法。但真正让机器"理解"复杂交通场景的&#xff0c;其实是背后那个能看懂图像、读懂文字、还能进行逻辑推理的"大脑&…...