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称为汇聚子类
  • 虚基类的构造函数是由最底层的派生类直接调用的,而不是由每个直接派生类调用。

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

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

相关文章

怎样把热门抖音短视频下载保存到手机相册?

怎样把热门抖音短视频下载保存到手机相册? 1、在手机上打开抖音短视频APP&#xff1b; 2、打开后搜索或找到要下载保存的抖音短视频&#xff1b; 3、打开短视频后&#xff0c;点击右则的分享&#xff0c;并滑动找到保存到相册&#xff1b; 4、点击后等待完成下载&#xff0c;…

Python实现接糖果小游戏

介绍: 基于Pygame的糖果从屏幕顶部下落的游戏代码。这个游戏包括了一个可以左右移动的篮子来接住下落的糖果&#xff0c;接住糖果会增加得分。 代码: import pygame import random import os# 初始化pygame和设置屏幕大小 pygame.init() screen_width, screen_height 800, 6…

海康视频播放,包含h5和web插件

自行下载 海康开放平台 demo 都写得很清楚&#xff0c;不多描述 1.视频web插件 vue2写法&#xff0c;公共vue文件写法&#xff0c;调用文件即可 开始时需要以下配置&#xff0c;不知道的找对接平台数据的人&#xff0c;必须要&#xff0c;否则播不了 getParameterData: {po…

万字总结随机森林原理、核心参数以及调优思路

万字总结随机森林原理、核心参数以及调优思路 在机器学习的世界里&#xff0c;随机森林&#xff08;Random Forest, RF&#xff09;以其强大的预测能力和对数据集的鲁棒性而备受青睐。作为一种集成学习方法&#xff0c;随机森林通过构建多个决策树并将它们的预测结果进行汇总&…

暴雨来袭,陈赫家变“水帘洞”网友:赫哥滴滴打船吗?

在魔都上海&#xff0c;一场突如其来的暴雨 不仅让街道变成了河流&#xff0c;还悄悄上演了一场现实版的“水帘洞”奇遇 而这场奇遇的主角&#xff0c;竟然是喜剧界的明星——陈赫&#xff01; 这天&#xff0c;乌云密布&#xff0c;电闪雷鸣 魔都的天空仿佛被捅了个窟窿 雨…

吴恩达《LangChain for LLM Application Development》课程笔记

目录 1. 前言 2. 课程笔记 2.1. 模型、提示和解析器 2.2. LLM记忆&#xff0c;上下文管理 2.3. 链式操作 2.4. 文档问答 2.4.1. stuff 方法 2.4.2. 其他方法 2.5. LLM应用评估 2.6. 代理 2.6.1. 预定义工具 2.6.2. 自定义工具 代码资源&#xff1a; 1. 前言 LangC…

文心一言 VS 讯飞星火 VS chatgpt (293)-- 算法导论21.4 2题

二、证明&#xff1a;每个结点的秩最多为 ⌊lgm⌋ 。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在数据结构和算法中&#xff0c;当我们谈论“结点的秩”时&#xff0c;这通常与某些特定的数据结构&#xff08;如B树或B树&#xff09;相关&#xff0c;其中每…

代码随想录算法训练营第40天| 518. 零钱兑换 II、 377. 组合总和 Ⅳ、70. 爬楼梯 (进阶)

518. 零钱兑换 II 题目链接&#xff1a;518. 零钱兑换 II 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 思路&#xff1a; 和494.目标和类似&#xff0c;这题属于组合问题&#xff0c;当我们有一个硬币coin时&#xff0c;对于每个金额j&#xff0c;通过添加这个硬币&a…

平安养老险陕西分公司参加2024上半年省级单位驻富平帮扶团联席会

6月28日&#xff0c;平安养老险陕西分公司工会副主席武媛携驻村工作队赴富平县庄里镇永安村参加2024上半年度省级单位驻富平帮扶团联席会议。 会议由省委金融办副主任、省委金融工委委员李嘉辉及省委金融办选派挂职干部、富平县副县长席玮共同主持。 会上&#xff0c;席玮县长带…

吴恩达机器学习 第三课 week2 推荐算法(下)

目录 01 学习目标 02 基于内容的过滤算法 03 实现“电影推荐系统” 3.1 问题描述 3.2 算法实现 04 大项目&#xff08;数据很大&#xff09;的推荐方法※ 4.1 方法原理 4.2 实施示例 05 总结 01 学习目标 &#xff08;1&#xff09;理解基于内容的过滤算法&#xff08…

嵌入式问题分析思路

BUG解决总体思路: 1.1 定位bug范围及性质 要有效解决问题&#xff0c;首先要缩小范围&#xff0c;集中关注最近的代码变化。这有助于迅速定位可能引入问题的部分&#xff0c;避免无谓的时间浪费。检查最近的代码提交记录和修改日志&#xff0c;找出可能影响现有功能的变更。然…

如果使用Outlook 2024出现问题

大家好&#xff0c;才是真的好。 很多企业使用Domino服务器当作POP/IMAP邮箱服务器来使用&#xff0c;虽然这不能发挥Domino最佳效能&#xff0c;但也不失为一种简单用法。 另一种企业则使用Domino仅作为应用app平台&#xff0c;邮箱早已迁移至O365或其他平台&#xff0c;他们…

报销又乱又慢,财务如何解决报销困局?

费用报销是企业频繁发生的业务场景&#xff0c;不同的企业在费用报销的流程、标准、制度、管理上各有不同。作为一些公司日常运作中的薄弱环节&#xff0c;费用报销环节存在着较大的内控风险&#xff0c;如&#xff1a;费用报销滞后&#xff0c;造成会计信息的失真&#xff0c;…

【YOLOv5/v7改进系列】更换损失函数为CIOU、GIOU、SIOU、DIOU、EIOU、WIOUv1/v2/v3、Focal C/G/S/D/EIOU等

一、导言 在目标检测任务中&#xff0c;损失函数的主要作用是衡量模型预测的边界框&#xff08;bounding boxes&#xff09;与真实边界框之间的匹配程度&#xff0c;并指导模型学习如何更精确地定位和分类目标。损失函数通常由两部分构成&#xff1a;分类损失&#xff08;用于…

我的世界服务器-高版本服务器-MC服务器-生存服务器-RPG服务器-幻世星辰

生存为主&#xff0c;RPG乐趣为辅&#xff0c;重视每位玩家的建议&#xff0c;一起打造心目中的服务器&#xff0c;与小伙伴一起探险我的世界&#xff01; 服务器版本: 1.18.2 ~ 1.20.4 Q群&#xff1a; 338238381 服务器官网: 星辰毛毛雨-Minecraft高版本生存服务器我的世界…

springboot是否可以代替spring

Spring Boot不能直接代替Spring&#xff0c;但它是Spring框架的一个扩展和增强&#xff0c;提供了更加便捷和高效的开发体验。以下是关于Spring Boot和Spring关系的详细解释&#xff1a; Spring框架&#xff1a; Spring是一个广泛应用的开源Java框架&#xff0c;提供了一系列模…

EDI是什么?与ERP有何关系

EDI的发展过程 电子数据交换&#xff08;Electronic Data Interchange&#xff0c;EDI&#xff09;是一种通过电子方式传输商业文件的技术。EDI的历史可以追溯到20世纪60年代&#xff0c;当时企业开始使用计算机进行数据处理。最早的EDI系统是为解决大型企业间的信息交换问题而…

nccl 04 nvidia 官方小程序

1&#xff0c;代码重新编辑 为了地毯式地检查结果的正确性&#xff0c;这里修改了代码 主要步骤为 step1: data_p指向的空间中&#xff0c;分别生成随机数&#xff1b; step2: 分别拷贝到gpu的sendbuff的显存中&#xff1b; step3: 通过nccl_all_reduce sum&#xff1b;…

掌握 Python 中 isinstance 的正确用法

&#x1f44b; 简介 isinstance() 函数用于判断一个对象是否是一个特定类型或者在继承链中是否是特定类型的实例。它常用于确保函数接收到的参数类型是预期的。 &#x1f4d6; 正文 1 语法 isinstance(object, classinfo) object参数是要检查的对象&#xff1b;classinfo参数…

【工具推荐】ONLYOFFICE8.1版本编辑器测评——时下的办公利器

文章目录 一、产品介绍1. ONLYOFFICE 8.1简介2. 多元化多功能的编辑器 二、产品体验1. 云端协作空间2. 桌面编辑器本地版 三、产品界面设计1. 本地版本2. 云端版本 四、产品文档处理1. 文本文档&#xff08;Word)2. 电子表格&#xff08;Excel&#xff09;3. PDF表单&#xff0…