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

C++编程(七)继承

文章目录

  • 一、继承
    • (一)概念
    • (二)语法格式
    • (三)通过子类访问父类中的成员
      • 1. 类内
      • 2. 类外
    • (四)继承中的特殊成员函数
      • 1. 构造函数
      • 2. 析构函数
      • 3. 拷贝构造函数
      • 4. 拷贝赋值函数
  • 二、多重继承
    • (一)概念
      • 1. 多重继承
      • 2. 语法格式
    • (二)使用示例
  • 三、链式继承
  • 四、扇形继承
  • 五、菱形继承(钻石继承)和虚继承
    • (一)概念
    • (二)语法格式
    • (三)使用示例
    • (四)虚继承

一、继承

(一)概念

继承是C++的一种机制,用已知的类封装出的新的类,继承描述类与类之间的关系

作用
为了代码的复用
为了实现多态的必备条件之一

继承中的访问控制权限:public private protected

A类继承B类:
A类叫做子类(派生类)
B类叫做父类(基类)

(二)语法格式

继承的语法格式

class 基类{};
class 子类:继承的权限 基类{};
  • 注:
  • 私有成员也可以被继承过来,但是私有成员被继承过来之后不能访问
  • 公有继承:访问权限不变,只有私有的成员访问不到
    私有继承:会将公有权限和受保护权限变为私有的,私有成员仍是私有成员,但是私有成员访问不到
    受保护继承:会将公有权限和受保护权限变为受保护的,私有成员继承过来还是不可访问
  • 一般继承方式都是public继承
    私有成员和受保护成员是访问不到的,如果想要访问私有成员和受保护成员可以借助基类的公有成员的接口
  • 如果不加继承控制权限,默认是private私有继承权限
  • 通过子类访问父类中的成员:
    在子类中访问父类中的成员:
    父类名::成员变量名;
    父类名::成员函数名;
    在类外通过子类访问父类中的成员:
    子类对象名.父类名::成员变量名;
    子类对象名.父类名::成员函数名;
  • 如果子类和父类中出现同名的成员变量名,不会起冲突;
    如果在子类中访问同名成员变量,什么都不加,默认是通过this指针

(三)通过子类访问父类中的成员

1. 类内

Father :: Father_show();

2. 类外

son.Father::Father_show();
#include <iostream>
using namespace std;
class Father{
public:int a=10;
};
class son:public Father{
public:void show(void){cout<<"a="<<Father::a<<endl;}
};int main()
{son son1;son1.show();return 0;
}

(四)继承中的特殊成员函数

构造函数、析构函数、拷贝构造函数、拷贝赋值函数

1. 构造函数

构造函数在继承关系中不会被继承
如果在子类的构造函数中没有显式的调用父类的构造函数,编译器会默认先调用父类的无参的构造函数
如果在子类的构造函数中显式地调用父类的构造函数,会先调用父类的构造函数,再调用子类的构造函数

#include <iostream>
using namespace std;
//基类
class Base
{
public:Base(int a): value(a) {cout<<"base"<<endl;}int value = 100;~Base(){cout<<"~base"<<endl;}
};
//子类
class Son1: Base  //说明不写访问控制权限,默认是private
{
public:Son1(int a): Base(a) {cout<<"son1"<<endl;}~Son1(){cout<<"~son1"<<endl;}
};
int main()
{Son1 son(10);   //实例化对象son2return 0;
}

在这里插入图片描述

2. 析构函数

1.析构函数在继承关系中不会被继承
2.如果子类中没有显式的调用析构函数,编译器会使用子类的析构函数;
编译器也会默认调用父类的析构函数;
3.如果在子类中重写了子类的析构函数,父类中重写父类的析构函数
先调用子类的析构函数----再调用父类的析构函数

3. 拷贝构造函数

1.如果在子类中不显式的调用父类的拷贝构造函数,
会调用编译器提供的缺省的拷贝构造函数来完成对成员的拷贝操作;
提供的缺省的拷贝构造函数是一个浅拷贝;

2.如果在子类中显式的调用父类的拷贝构造函数,会调用自己写的拷贝构造函数;
想要调用父类的拷贝构造函数需要在子类的拷贝构造函数的初始化列表中显式的调用父类的拷贝构造函数;
eg:
//父类的指针或者是引用指向子类的对象—多态中讲
子类类名(const 子类类名 &obj): 父类类名(传参){}

3.如果在类中没有指针类型的成员,可以使用编译器提供的缺省的拷贝构造函数; //浅拷贝
如果在类中有指针类型的成员,需要自己实现深拷贝构造函数

#include <iostream>using namespace std;
class Base
{
public:Base(int a): data(a){cout << "Base(int a):data(a)" << endl;}~Base(void){cout << " ~Base(void)" << endl;}//拷贝构造函数Base(const Base &obj){cout << "Base(const Base &obj)"  << endl;data = obj.data;}
private:int data;
};
class Son: public Base
{
public:Son(int a): Base(a){cout << "Son(int a):Base(a)" << endl;}~Son(void){cout << " ~Son(void)" << endl;}//子类的拷贝构造函数//父类的指针或者是引用指向子类的对象(多态中讲)Son(const Son &obj): Base(obj){cout << " Son(const Son &obj):Base(obj)" << endl;}
private:
};int main()
{//实例化对象//Son son1;  //调用无参构造函数Son son1(10);   //调用有参构造函数Son son2 = son1;  // 调用拷贝构造函数return 0;
}

4. 拷贝赋值函数

1.如果在子类中不显式的调用父类的拷贝赋值函数,会调用编译器提供的缺省的拷贝赋值函数 来完成对成员的拷贝赋值操作;
默认提供的拷贝赋值函数是一个浅拷贝;

2.如果在子类中想要显式的调用父类的拷贝赋值函数,需要在子类的拷贝赋值函数中使用调用父类的拷贝赋值函数
格式:
父类::成员函数(传递参数); //需要在子类的拷贝赋值函数中写

3.如果在类中没有指针类型的成员,可以使用编译器提供的默认缺省的拷贝赋值函数
如果在类中有指针类型的成员,需要自己实现深拷贝赋值函数

#include <iostream>using namespace std;
class Base
{
public:Base(int a): data(a){cout << "Base(int a):data(a)" << endl;}~Base(void){cout << " ~Base(void)" << endl;}//拷贝赋值函数Base &operator =(const Base &obj){cout << "Base &operator =(const Base &obj)" << endl;if(this != &obj) {//拷贝赋值操作data = obj.data;}return *this;}
private:int data;
};
class Son: public Base
{
public:Son(int a): Base(a){cout << "Son(int a):Base(a)" << endl;}~Son(void){cout << " ~Son(void)" << endl;}//拷贝赋值函数Son &operator =(const Son &obj){cout << "Son &operator =(const Son &obj)" << endl;if(this != &obj) {//拷贝赋值函数//想要显式的使用父类的拷贝赋值函数//调用父类的拷贝赋值函数//父类的指针或者是引用指向子类对象(多态中讲)Base::operator =(obj);}return *this;}
private:
};int main()
{//实例化对象//Son son1;  //调用无参构造函数Son son1(10);   //调用有参构造函数Son son3(11);son1 = son3;  //调用拷贝赋值函数return 0;
}

二、多重继承

(一)概念

1. 多重继承

一个子类继承于多个父类叫做多重继承

2. 语法格式

class 基类1{};
class 基类2{};
class 子类:public 基类1,public 基类2{};

实际开发中不建议使用多重继承,因为在不同的基类中包含相同名字的成员,容易出现歧义,如果不想出现歧义,需要通过子类访问父类中的成员;
格式:子类对象名.父类名::成员;

(二)使用示例

#include <iostream>
using namespace std;
class Base1{
public:int a=10;
};
class Base2{
public:int a=200;
};class son:public Base1,public Base2{
};int main()
{son son1;cout<<"Base1::a="<<son1.Base1::a<<" Base2::a="<<son1.Base2::a<<endl;return 0;
}

输出结果
在这里插入图片描述

注意
如果此时直接调用son1中的a会报错,因为son1从base1和base2中都继承了a,所以当直接调用时,会产生歧义,导致编译器无法确定是打印从哪个基类继承的值
在这里插入图片描述

三、链式继承

链式继承中构造函数的初始化列表只需要关注自己继承的基类即可

#include <iostream>
using namespace std;
class Grandfather{
public:Grandfather(int aa):a(aa){cout<<"Grandfather 构造函数"<<endl;}~Grandfather(void){cout<<"Grandfather 析构函数"<<endl;}int a=10;
};class Father:public Grandfather{
public:Father(int aa,int bb):b(bb),Grandfather(aa){cout<<"Father 构造函数"<<endl;}~Father(void){cout<<"Father 析构函数"<<endl;}int b=20;
};class son:public Father{
public:son(int aa,int bb,int cc):c(cc),Father(aa,bb){cout<<"son 构造函数"<<endl;}~son(void){cout<<"son 析构函数"<<endl;}int c=30;
};int main()
{son son1(100,200,300);return 0;
}

输出结果
在这里插入图片描述

四、扇形继承

扇形继承中子类的初始化列表需要把所有基类都考虑进去

#include <iostream>
using namespace std;
class Mother{
public:Mother(int aa):a(aa){cout<<"Mother 构造函数"<<endl;}~Mother(void){cout<<"Mother 析构函数"<<endl;}int a=10;
};class Father{
public:Father(int bb):b(bb){cout<<"Father 构造函数"<<endl;}~Father(void){cout<<"Father 析构函数"<<endl;}int b=20;
};class son:public Mother,public Father{
public:son(int aa,int bb,int cc):c(cc),Mother(aa),Father(bb){cout<<"son 构造函数"<<endl;}~son(void){cout<<"son 析构函数"<<endl;}int c=30;
};int main()
{son son1(100,200,300);return 0;
}

输出结果
在这里插入图片描述

五、菱形继承(钻石继承)和虚继承

(一)概念

虚继承是一种机制,作用是就是为了解决钻石继承中继承多份父类数据的问题
虚继承共享同一份数据,虚继承会间接或是直接影响基类或者子类的数据

(二)语法格式

class 子类类名: virtual 继承方式 基类类名{}

(三)使用示例

#include <iostream>
using namespace std;
class Base{
public:Base(int b):base(b){cout<<"Base 构造函数"<<endl;}~Base(void){cout<<"Base 析构函数"<<endl;}int base=10000;
};class Mother:public Base{
public:Mother(int aa,int base):Base(base),a(aa){cout<<"Mother 构造函数"<<endl;}~Mother(void){cout<<"Mother 析构函数"<<endl;}int a=10;
};class Father:public Base{
public:Father(int bb,int base):Base(base),b(bb){cout<<"Father 构造函数"<<endl;}~Father(void){cout<<"Father 析构函数"<<endl;}int b=20;
};class son:public Mother,public Father{
public:son(int aa,int bb,int cc,int base):Mother(aa,base),Father(bb,base),c(cc){cout<<"son 构造函数"<<endl;}~son(void){cout<<"son 析构函数"<<endl;}int c=30;
};int main()
{son son1(100,200,300,1);return 0;
}

输出结果
在这里插入图片描述
但是如果此时想要调用son1.base就会产生歧义,因为son1从两个父类中都分别继承了一个base,继承类继承了基类多次,从而产生了歧义
在这里插入图片描述

(四)虚继承


#include <iostream>
using namespace std;
//虚基类
class Base{
public:Base(int b):base(b){cout<<"Base 构造函数"<<endl;}~Base(void){cout<<"Base 析构函数"<<endl;}int base=10000;
};
//加上关键字virtual声明成虚基类
class Mother:virtual public Base{
public:Mother(int aa,int base):Base(base),a(aa){cout<<"Mother 构造函数"<<endl;}~Mother(void){cout<<"Mother 析构函数"<<endl;}int a=10;
};
//加上关键字virtual声明成虚基类
class Father:virtual public Base{
public:Father(int bb,int base):Base(base),b(bb){cout<<"Father 构造函数"<<endl;}~Father(void){cout<<"Father 析构函数"<<endl;}int b=20;
};//汇聚子类
class son:public Mother,public Father{
public:son(int aa,int bb,int cc,int base):Base(base),Mother(aa,base),Father(bb,base),c(cc){//虚基类的构造函数是由最底层的派生类直接调用的,而不是由每个直接派生类调用。        cout<<"son 构造函数"<<endl;}~son(void){cout<<"son 析构函数"<<endl;}int c=30;
};int main()
{son son1(100,200,300,1);cout<<son1.a<<endl;cout<<son1.b<<endl;cout<<son1.c<<endl;cout<<son1.base<<endl;return 0;
}
  • 注:
  • 此时基类Base被称作虚基类,子类son1称为汇聚子类
  • 虚基类的构造函数是由最底层的派生类直接调用的,而不是由每个直接派生类调用。

相关文章:

C++编程(七)继承

文章目录 一、继承&#xff08;一&#xff09;概念&#xff08;二&#xff09;语法格式&#xff08;三&#xff09;通过子类访问父类中的成员1. 类内2. 类外 &#xff08;四&#xff09;继承中的特殊成员函数1. 构造函数2. 析构函数3. 拷贝构造函数4. 拷贝赋值函数 二、多重继承…...

【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering

【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering 一、前言Abstract1 INTRODUCTION2 RELATED WORK2.1 Traditional Scene Reconstruction and Rendering2.2 Neural Rendering and Radiance Fields2.3 Point-Based Rendering and Radiance Fields 3 O…...

【TB作品】atmega16 计算器,ATMEGA16单片机,Proteus仿真

实验报告&#xff1a;基于ATmega16单片机的简易计算器设计 1. 实验背景 计算器是日常生活和工作中不可或缺的工具&#xff0c;通过按键输入即可实现基本的四则运算。通过本实验&#xff0c;我们将利用ATmega16单片机、矩阵键盘和LCD1602显示屏&#xff0c;设计并实现一个简易…...

C++的IO流操作

文章目录 C语言的输入与输出流是什么CIO流C标准IO流C文件IO流二进制读写文本读写 stringstream的简单介绍 C语言的输入与输出 C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放…...

MacOS升级指定Python版本的pip

场景&#xff1a; 系统默认是Python2.7&#xff0c;已经通过brew install python3.11 python3.12安装了多个版本的Python 执行&#xff1a;pip --version pip 24.1 from /Users/mac10.12/Library/Python/3.11/lib/python/site-packages/pip (python 3.11) 用的是Python3.11…...

音频Balance源码总结

音频Balance源码总结 何为音频Balance&#xff1f; 顾名思义&#xff0c;Balance及平衡&#xff0c;平衡也就是涉及多方&#xff0c;音频左右甚至四通道&#xff0c;调节所有通道的音量比&#xff0c;使用户在空间内听到各个通道的音频大小不一&#xff0c;好似置身于真实环境…...

CesiumJS【Basic】- #043 绘制脉冲线(Entity方式)- 需要自定义着色器

文章目录 绘制脉冲线(Entity方式)- 需要自定义着色器1 目标2 代码2.1 main.ts3 资源文件绘制脉冲线(Entity方式)- 需要自定义着色器 1 目标 使用Entity方式绘制脉冲线 2 代码 2.1 main.ts import * as Cesium from cesium;const viewer = new Cesium.Viewer(cesiumCont…...

Linux命令 wc(word count)-l(lines)用于统计文件中的行数。

文章目录 1、wc -l2、实战3、wc --help 1、wc -l 在命令 wc -l 中&#xff0c;-l 的英文全称是 lines。这个选项用于指定 wc&#xff08;word count&#xff0c;单词计数&#xff09;命令来统计文件的行数。 例如&#xff0c;当你运行 wc -l load_user_100w_sort.sql 时&…...

数据结构 - C/C++ - 链表

目录 结构特性 内存布局 结构样式 结构拓展 单链表 结构定义 节点关联 插入节点 删除节点 常见操作 双链表 环链表 结构容器 结构设计 结构特性 线性结构的存储方式 顺序存储 - 数组 链式存储 - 链表 线性结构的链式存储是通过任意的存储单元来存储线性…...

sheng的学习笔记-AI-高斯混合模型(GMM)

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 需要学习前置知识&#xff1a; 聚类&#xff0c;可参考 sheng的学习笔记-AI-聚类(Clustering)-CSDN博客 EM算法&#xff0c;可参考 sheng的学习笔记-AI-EM算法-CSDN博客 贝叶斯&#xff0c;可参考 sheng的学习笔记-AI-…...

OFDM的缺点与关键技术

子载波间干扰英文简写ICI&#xff0c;ICI可能由各种原因引起 在多径信道中&#xff0c;CP小于最大附加时延时收发系统载波频率偏差和采样偏差收发系统相对移动&#xff0c;存在多普勒频移 ICI是制约OFDM系统性能的主要重要因素之一 对频率偏差敏感----->同步技术&#xff0…...

电脑录音软件哪个好?7款录制音频工具大盘点,赶快学起来!(2024)

也许你渴望提取你最喜欢的节目的背景音乐&#xff0c;或者你希望录制自己的声音制作教程。如果是这样&#xff0c;你就需要一款优秀的电脑录音软件&#xff0c;来帮助你捕捉任何你想要的声音&#xff0c;而且不会损失音质。目前市场上存在着大量的录制音频工具&#xff0c;面对…...

【Android面试八股文】你说你使用Leakcanary进行内存泄漏检测,那你能说一说Leakcanary的原理吗?

文章目录 一、 Java四大引用二、 LeakCanary示例工作机制注意事项三、 Leakcanary的原理四、 Leakcanary的源码分析LeakCanary#Install创建RefWatcherAndroidRefWatcherBuilder#buildAndInstall监听Activity的引用 : ActivityRefWatcher检查引用Dump Heap解析hprof定位泄露的引…...

蒂升电梯职业性格和Verify认知能力SHL测评答题攻略及薪资待遇解密!

​一、蒂升电梯职业性格和认知能力测评考什么 您好&#xff01;蒂升电梯公司邀请您参加的OPQ职业性格测评和Verify认知能力测评是两种常见的评估工具&#xff0c;用于帮助了解个人的职场性格特点和认知能力。 OPQ职业性格测评 这是一种性格测试&#xff0c;通常用于评估个人在…...

window上部署sql server改动端口、和sqlserver的一些还原、批量插入存储过程的命令

1.端口的查看和启动 --windows上安装上sql server数据库后&#xff0c;搜索界面搜索sql&#xff0c;会出现配置管理器&#xff0c;点击进入 --进入后再次选择配置管理器 2. sqlserver数据库还原图形化 sqlserver还原数据库时会使数据库进入一个restore的还原状态&#xff0c;…...

【单片机与嵌入式】stm32串口通信入门

一、串口通信/协议 &#xff08;一&#xff09;串口通信简介 串口通信是一种通过串行传输方式在电子设备之间进行数据交换的通信方式。它通常涉及两条线&#xff08;一条用于发送数据&#xff0c;一条用于接收数据&#xff09;&#xff0c;适用于各种设备&#xff0c;从微控制…...

启动Redis服务器

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。 ——苏轼 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、在 Linux 或 macOS 上启动 Redis二、在 Windows 上启动 Redis三、配置 Redis 为服务启动&…...

uniapp中使用threejs加载几何体

我的建议是使用这个库 https://github.com/deepkolos/three-platformize 为什么&#xff1f;我试了uniapp推荐的和threejs-miniprogram这个小程序官方库&#xff0c;都加载不出来我的obj模型。所有我推荐不要用obj模型最好&#xff0c;挺多都支持GLTF模型的&#xff0c;但是我不…...

【SQL注入】 数据库基础

MySQL中的库名 information_schema&#xff08;信息库&#xff09;—— 保存其他数据库里所有信息&#xff08;数据库名、表、字段的数据类型/访问权限&#xff09; mysql—— 存储用户名 密码 host performance_schema——内存数据库 数据放在内存中直接操作的数据库 sys—…...

文件操作~

目录 1.为什么使用文件&#xff1f; 2.什么是文件&#xff1f; 2.1 程序文件 2.2 数据文件 2.3 文件名 3.⼆进制文件和文本文件&#xff1f; 4.文件的打开和关闭 4.1 流和标准流 4.1.1 流 4.1.2 标准流 4.2 文件指针 4.3 ⽂件的打开和关闭 5.文件的顺序读写 5.1 …...

电力系统时间同步系统之三

2.6 电力系统时间同步装置 时间同步装置主要完成时间信号和时间信息的同步传递&#xff0c;并提供相应的时间格式和物理接口。时间同步装置主要由三大部分组成&#xff1a;时间输入、内部时钟和时间输出&#xff0c;如图 2-25 所示。输入装置的时间信号和时间信息的精度必须不…...

【HarmonyOS 5】教育开发实践详解以及详细代码案例

以下是基于 ‌HarmonyOS 5‌ 的教育应用开发实践详解及核心代码案例&#xff0c;结合分布式能力与教育场景需求设计&#xff1a; 一、教育应用核心开发技术 ‌ArkTS声明式UI‌ 使用 State 管理学习进度状态&#xff0c;LocalStorageProp 实现跨页面数据同步&#xff08;如课程…...

C++中const关键字详解:不同情况下的使用方式

在 C 中&#xff0c;const 关键字用于指定一个对象或变量是常量&#xff0c;意味着它的值在初始化之后不能被修改。下面详细介绍 const 修饰变量、指针、类对象和类中成员函数的区别以及注意事项。 修饰变量 详细介绍 当 const 修饰变量时&#xff0c;该变量成为常量&#x…...

【HarmonyOS 5】出行导航开发实践介绍以及详细案例

以下是 ‌HarmonyOS 5‌ 出行导航的核心能力详解&#xff08;无代码版&#xff09;&#xff0c;聚焦智能交互、多端协同与场景化创新&#xff1a; 一、交互革新&#xff1a;从被动响应到主动服务 ‌意图驱动导航‌ ‌自然语义理解‌&#xff1a;用户通过语音指令&#xff08;如…...

Lifecycle 核心原理面试回答

1. 核心目标与设计思想 解耦生命周期管理&#xff1a; 将 Activity/Fragment 的生命周期回调逻辑从视图控制器中剥离&#xff0c;让业务组件&#xff08;如 Presenter, Repository 封装&#xff09;能独立感知生命周期。 状态驱动&#xff1a; 将离散的生命周期事件 (ON_CREAT…...

基于SFC的windows系统损坏修复程序

前言 在平时使用Windows操作系统时会遇到很多因为系统文件损坏而出现的错误 例如:系统应用无法打开 系统窗口(例如开始菜单)无法使用 电脑蓝屏或者卡死 是如果想要修复很多人只能想到重装系统。但其实Windows有一个内置的系统文件检查器可以修复此类错误。 原理 SFC命令…...

机器学习算法时间复杂度解析:为什么它如此重要?

时间复杂度的重要性 虽然scikit-learn等库让机器学习算法的实现变得异常简单&#xff08;通常只需2-3行代码&#xff09;&#xff0c;但这种便利性往往导致使用者忽视两个关键方面&#xff1a; 算法核心原理的理解缺失 忽视算法的数据适用条件 典型算法的时间复杂度陷阱 SV…...

Mac 双系统

准备——Windows10 ISO文件下载 下载地址&#xff1a;https://msdn.itellyou.cn 操作系统 Win10-1903镜像 复制链接迅雷下载 第一步——查看系统磁盘剩余空间 打开“启动台”找到“其他”文件夹&#xff0c;打开“磁盘工具”&#xff08;剩余空间要大于40GB&#xff09; 第二…...

Java调用大模型API实战指南

文章目录 前言调用大模型的流程概述和基本原理获取 DeepSeek 的 API keyJava 实现调用大模型 API 的Demo进阶扩展建议 前言 随着大语言模型&#xff08;如 OpenAI、DeepSeek、通义千问等&#xff09;的发展&#xff0c;我们可以很方便地用 API 接口调用这些强大的智能助手。在…...

11.MySQL事务管理详解

MySQL事务管理详解 文章目录 MySQL事务管理 事务的概念 事务的版本支持 事务的提交方式 事务的相关演示 事务的隔离级别 查看与设置隔离级别 读未提交&#xff08;Read Uncommitted&#xff09; 读提交&#xff08;Read Committed&#xff09; 可重复读&#xff08;Repeatabl…...