05-C++ 类和对象-继承

类与对象-03

继承与派生

1. 继承的概念

c++最重要的特征是代码重用,通过继承机制可以利用已有的数据类型,来定义新的数据类型,新的类不仅拥有旧类的成员,还拥有新定义的成员。

一个 B 类继承于 A 类,或称从类 A 派生类 B。这样的话,类 A 成为基类(父类),类 B 成为派生类(子类)。

派生类中的成员,包含两大部分:

  • 一类是从基类继承过来的,
  • 一类是自己增加的成员。

从基类继承过过来的表现其共性,而新增的成员体现了其个性。

2. 继承的优点

1)减少重复的代码,减轻程序整体的体量。

2)继承的好处,可以将共性的内容封装成一个基类(父类),遇到专项业务时,可以扩展基类变为一个新类,在新类中重点扩展功能。

3. 继承的语法

class 子类:继承方式 父类名
{ 
	子类新增自己的数据和方法;
};

4. 继承方式

  • public(推荐):子类将 原封不动的继 承父类成员,但是 不能直接访问 父类 私有的成员

  • protected:子类 继承到 父类的成员 转换为 protected修饰的成员,但是 不能直接访问 父类 私有的成员

  • private:子类将 继承到所有父类成员 转换为 私有的成员,但是 不能直接访问 父类 私有的成员

在这里插入图片描述

示例1:public

#include <iostream>
using namespace std;
class A
{
public:
    int a;
    void testA()
    {
        cout << "testA" << endl;
    }
};
class B:public A
{
};
int main(int argc, char *argv[])
{
    B b;
    b.a = 10;
    b.testA();  //testA
    return 0;
}

示例2:protected ,若是protected继承,父类中的public将变为 protected,只能在当前类或子类中使用。

#include <iostream>
using namespace std;
class A
{
public:
    int a;
    void testA()
    {
        cout << "testA" << endl;
    }
};
class B:protected A
{
public:
    void testB()
    {
        cout << a << endl;
        testA();
    }
};
int main(int argc, char *argv[])
{
    B b;
    //此时是protected继承,父类中的public将变为 protected,只能在当前类或子类中使,
    //所以下面报错
    //b.a = 10;//报错
    //b.testA();//报错
    b.testB(); //93 testA
    return 0;
}

5. 注意

  1. 子类可以继承父类所有成员,但是父类私有成员不可访问
  2. 子类 不能继承父类构造函数拷贝构造析构函数,但是子类中可以调用
  3. 子类可以多继承
  4. 子类在 创建对象 时会 调用父类构造函数,如果 没有明确 写出 调用的父类构造 函数,默认调用 父类无参构造 ,此时如果父类 没有无参构造,程序报错
  5. 子类调用父类构造函数,在 子类构造函数后使用初始化列表方式调用父类构造函数
  6. operator=不能被继承

示例:

#include <iostream>
#include <cstring>
using namespace std;
class Anim{
private:
    char type[50];
    int age;
    char sex[10];
public:
    Anim(){
        cout << "Anim无参构造" << endl;
    }
    Anim(char *type,char *sex,int age)
    {
        strcpy(this->type,type);
        strcpy(this->sex,sex);
        this->age = age;
        cout << "Anim有参构造" << endl;
    }
    Anim(const Anim& anim)
    {
        strcpy(this->type,anim.type);
        strcpy(this->sex,anim.sex);
        this->age = anim.age;
    }
    void setType(char *type)
    {
        strcpy(this->type,type);
    }
    char* getType()
    {
        return type;
    }
    void setSex(char *sex)
    {
        strcpy(this->sex,sex);
    }
    char* getSex()
    {
        return sex;
    }
    void setAge(int age)
    {
        this->age = age;
    }
    int getAge()
    {
        return age;
    }
};
class A{

};
//3、子类可以多继承
class Yang:public Anim,public A
{
public:
    Yang(){}

    //5、初始化列表调用父类构造函数
    Yang(char *type,char *sex,int age):Anim(type,sex,age){

    }
};

int main(int argc, char *argv[])
{
    //Yang y;
    //1、子类可以继承父类所有成员,但是父类私有成员不可访问
    //y.age;
    //2、子类不能继承父类的构造函数,拷贝构造,析构函数
    //Yang y("绵羊","公",18); //Anim有参构造
    //4、创建子类对象时会调用父类构造函数
    //默认调用父类无参构造
    //Yang y;
    //如果子类构造函数在初始化列表中指定调用父类的构造函数
    //那么就不会默认调用父类无参构造
    //Yang y("山羊","公",3);
    //如果父类中没有无参构造,子类没有明确写出调用父类构造函数
    //此时子类将调用父类无参构造,但是父类没有无参构造
    //程序报错
    Yang y;
    return 0;
}

6. 构造与析构的执行顺序

继承中的构造和析构:

  • 子类对象在创建时会首先调用父类的构造函数
  • 父类构造函数执行完毕后,才会调用子类的构造函数
  • 当父类构造函数有参数时,需要在子类初始化列表(参数列表)中显示调用父类构造函数
  • 析构函数调用顺序和构造函数相反

在这里插入图片描述

示例1:子类继承父类

#include <iostream>

using namespace std;
class A{
public:
    A(){
        cout << "A的构造函数" << endl;
    }
    ~A(){
        cout << "A的析构函数" << endl;
    }
};
class B:public A{
public:
    B(){
        cout << "B的构造函数" << endl;
    }
    ~B(){
        cout << "B的析构函数" << endl;
    }
};
int main(int argc, char *argv[])
{
    B b;
    return 0;
}
//A的构造函数
//B的构造函数
//B的析构函数
//A的析构函数

示例2:子类继承父类,该子类中还要其他类的成员

#include <iostream>

using namespace std;
class A{
public:
    A(){
        cout << "A的构造函数" << endl;
    }
    ~A(){
        cout << "A的析构函数" << endl;
    }
};
class C{
public:
    C(){
        cout << "C的构造函数" << endl;
    }
    ~C(){
        cout << "C的析构函数" << endl;
    }
};
class B:public A{
private:
    C c;
public:
    B(){
        cout << "B的构造函数" << endl;
    }
    ~B(){
        cout << "B的析构函数" << endl;
    }
};
int main(int argc, char *argv[])
{
    B b;
    return 0;
}
//A的构造函数
//C的构造函数
//B的构造函数
//B的析构函数
//C的析构函数
//A的析构函数

7. 继承中父子类成员重名

7.1 成员变量重名

调用方式:

  • 操作子类成员变量:子类对象.成员变量名
  • 操作父类提供的成员变量:子类对象.父类名::成员变量名

示例:

#include <iostream>

using namespace std;
class Basic{
public:
    int x;
    int y;
    Basic(int x):x(x){}
};
class Son:public Basic{
public:
    int x;
    //子类构造函数中必须调用父类构造函数
    //默认调用父类无参构造
    Son(int x1, int x2):Basic(x1){
        this->x = x2;
    }
};

int main(int argc, char *argv[])
{
    Son son(10,100);
    //当父子类成员变量重名时
    //此时子类对象中有两个名称相同的变量
    //1个是继承父类的
    //1个是子类特有的
    //获取子类特有的该变量
    cout << son.x << endl;//100
    //获取父类提供的x变量
    cout << son.Basic::x << endl;//10
    //没有重名的成员直接获取
    cout << son.y << endl; //随机数
    return 0;
}
7.2 成员函数重名

概念:

  • 子类成员函数名父类成员函数名 重名,此时 子类该函数就是对父类名为该函数名的函数进行 重定义
  • 重定义
    • 继承关系中
    • 子类函数名与父类函数名相同
  • 特点:屏蔽父类该函数

调用方式:

  • 操作子类成员 函数:子类对象.成员函数名(实参列表)
  • 操作父类提供的成员函数:子类对象.父类名::成员函数名(实参列表)

示例:

#include <iostream>

using namespace std;
class Fu{
public:
    void test(){
        cout << "fu test()" << endl;
    }
    void test(int a){
        cout << "fu test(int)" << endl;
    }
    void test(int a, int b){
        cout << "fu test(int, int)" << endl;
    }
    void fun01(){
        cout << "fu fun01()" << endl;
    }
};
class Zi:public Fu{
public:
    void test(){
        cout << "zi test()" << endl;
    }
};

int main(int argc, char *argv[])
{
    Zi zi;
    //当父子类函数名重名时
    //子类调用重名函数,默认调用的是子类自己的函数
    zi.test();      //zi test()
    //子类调用继承于父类的 重名函数
    zi.Fu::test();  //fu test()
    zi.Fu::test(1);  //fu test(int)
    zi.Fu::test(10,20);  //fu test(int, int)

    //子类调用继承于父类的 非重名函数
    zi.fun01();     //fu fun01()
    return 0;
}

8. 多继承

概念:一个子类继承与 多个父类

语法:

class 子类名:继承方式1 父类1, 继承方式2 父类2, ...
{
	子类特有成员
}

父类构造顺序:

  • 子类对象创建时,按继承 编写的顺序 依次执行父类对象构造,与子类构造函数后初始化列表中的顺序无关

示例1:

#include <iostream>

using namespace std;
class A{
public:
    int x;
    A(int a):x(a){}
};
class B{
public:
    int x;
    B(int a):x(a){}
};
class C:public A,public B
{
public:
    int x;
    C(int a,int b,int c):x(a),A(b),B(c){}
};
int main(int argc, char *argv[])
{
    C c(1,2,3);
    //获取c类中的x
    cout << c.x << endl;    //1
    //获取c类中继承与A类的x
    cout << c.A::x << endl; //2
    //获取c类中继承与B类的x
    cout << c.B::x << endl; //3
    return 0;
}

示例2:

#include <iostream>

using namespace std;
class A{
    public:
    A(){
        cout << "A的构造函数" << endl;
    }
    ~A(){
        cout << "A的析构函数" << endl;
    }

};
class B{
    public:
    B(){
        cout << "B的构造函数" << endl;
    }
    ~B(){
        cout << "B的析构函数" << endl;
    }
};
class C:public B,public A{
    public:
    C():A(),B(){
        cout << "C的构造函数" << endl;
    }
    ~C(){
        cout << "C的析构函数" << endl;
    }
};
int main(int argc, char *argv[])
{
    C c;
    return 0;
}
//B的构造函数
//A的构造函数
//C的构造函数
//C的析构函数
//A的析构函数
//B的析构函数

9. 菱形继承(了解)

概念:

A的子类A1与A2

B类多继承A1与A2类

此时这种关系称为菱形继承

注意:

  • 菱形继承会导致子类用于多份祖先数据,当孙子类调用成员(函数或数据)时,会产生二义性。
  • 如:
    • A类中提供num成员变量
    • A1与A2类属于A的子类,,那么A1与A2类将各自拥有一份num
    • B作为A1与A2的子类,那么 B将拥有两个num

在这里插入图片描述

示例:

#include <iostream>
#include <cstring>
using namespace std;
class Anim{
public:
    char name[50];
    Anim(char *name)
    {
        strcpy(this->name, name);
    }
};
class Yang:public Anim{
public:
    Yang(char *name):Anim(name)
    {

    }
};
class Tuo:public Anim{
public:
    Tuo(char *name):Anim(name)
    {

    }
};
class YangTuo:public Yang, public Tuo{
public:
    YangTuo(char *name01, char *name02):Yang(name01),Tuo(name02)
    {

    }
};
int main(int argc, char *argv[])
{
    YangTuo yt("tom", "jerry");
    cout << yt.Yang::name << endl;  //tom
    cout << yt.Tuo::name << endl;   //jerry
    
    cout << &(yt.Yang::name) << endl;   //0x61fe2c
    cout << &(yt.Tuo::name) << endl;    //0x61fe5e

    return 0;
}

菱形继承类布局:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

10. 虚继承

概念:使用 virtual修饰继承关系

语法:

class 子类名:virtual 继承关系 父类名
{

};

解决问题:

解决菱形继承的调用二义性,多个类只保存一份相同数据

如:

  • A类中提供num成员变量
  • A1与A2类属于A的子类,那么A1与A2类将各自拥有一份num
  • B作为A1与A2的子类,那么B将拥有两个num,此时调用num会出现二义性
  • 所以只能虚继承使其存储一个num.

示例:

#include <iostream>
#include <cstring>
using namespace std;
class Anim{
public:
    char name[50];
    Anim(char *name)
    {
        strcpy(this->name, name);
    }
};
class Yang:virtual public Anim{
public:
    Yang(char *name):Anim(name)
    {

    }
};
class Tuo:virtual public Anim{
public:
    Tuo(char *name):Anim(name)
    {

    }
};
class YangTuo:public Yang, public Tuo{
public:
    YangTuo(char *name01, char *name02):Anim(name01),Yang(name01),Tuo(name02)
    {

    }
};

int main(int argc, char *argv[])
{
    YangTuo yt("tom", "jerry");
    cout << yt.Yang::name << endl;  //tom
    cout << yt.Tuo::name << endl;   //tom

    cout << &(yt.Yang::name) << endl;   //0x61fe5c
    cout << &(yt.Tuo::name) << endl;    //0x61fe5c
    return 0;
}

虚继承类布局:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QCheckBoxQRadioBoxQComboBoxQSlider

QCheckBox QCheckBox 是 Qt 框架中一个常用的控件&#xff0c;用于创建一个可以勾选或取消勾选的复选框。它通常用于表示选项的开/关状态 autoExclusive 是一个与单选按钮&#xff08;QRadioButton&#xff09;相关的属性。这个属性决定了同一个父窗口下的单选按钮是否自动形成…

【C++干货铺】STL中set和map的介绍和使用

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 序列式容器 关联式容器 键值对 树形结构的关联式容器 set set的介绍 set的使用 set的模板参数列表 set的构造 ​编辑 set的容量 set的删除和查找 mult…

125 验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回 true &#xff1b;否则&#…

软件测试/测试开发丨Python常用数据结构-列表list

列表的定义 列表是有序的可变元素的集合&#xff0c;使用中括号[ ]包围&#xff0c;元素之间用逗号分隔&#xff1b;列表是动态的&#xff0c;可以随时扩展和收缩&#xff1b;列表是异构的&#xff0c;可以同时存放不同类型的对象&#xff1b;列表允许出现重复的元素。 列表的…

电子企业实施MES管理系统需要多少预算

在当今高度自动化的工业环境中&#xff0c;MES管理系统已成为提升生产效率、优化资源配置、确保产品质量的关键工具。对于电子企业而言&#xff0c;实施MES管理系统不仅可以提升生产过程的透明度&#xff0c;还能有效降低成本&#xff0c;增强市场竞争力。然而&#xff0c;企业…

SV接口的驱动和采样_2023.12.27】

cb 使用cloking block进行信号的同步 在cloking block&#xff0c;所有信号的采样和驱动&#xff0c;都是和时钟同步的 clocking cb &#xff08;posedge clk&#xff09;; input grant; output request; endclocking接口同步 用和wait来同步测试平台中的信号 bus.cb; 接口…

uboot安装操作系统

FT1500A 刀片机uboot安装系统 外接sata盘的方式&#xff1a; 准备一个带系统的sata盘&#xff08;系统必须支持这个硬件不然启不来&#xff0c;uboot不需要改什么默认进这个系统&#xff09;&#xff0c;把iso与脚本harddisk_copy-noarch_20160711.sh拷进去 通过mobaxterm或…

《Python》:深拷贝、浅拷贝、赋值之间的关系(附可变与不可变)【用图文讲清楚!】

背景 想必大家面试或者平时学习经常遇到问python的深拷贝、浅拷贝和赋值之间的区别了吧&#xff1f;看网上的文章很多写的比较抽象&#xff0c;小白接收的难度有点大&#xff0c;于是乎也想自己整个文章出来供参考 可变与不可变 讲深拷贝和浅拷贝之前想讲讲什么是可变数据类型…

Kubernetes 学习总结(43)—— Kubernetes 从提交 deployment 到 pod 运行的全过程

当用户向 Kubernetes 提交了一个创建 deployment 的请求后&#xff0c;Kubernetes 从接收请求直至创建对应的 pod 运行这整个过程中都发生了什么呢&#xff1f; kubernetes 架构简述 在搞清楚从 deployment 提交到 pod 运行整个过程之前&#xff0c;我们有先来看看 Kubernete…

【unity学习笔记】配置模型,实现眨眼和口型效果

一、vriod捏人 1.在vroidstudio软件中捏人 2.导出模型&#xff08;.vrm) 二、vrid导入unity的插件 1.在Git上搜索、打开univrm。 2.找到release页面找到合适的插件版本。&#xff08;VRM-0.116.0_0f6c&#xff09; 3.将univrm导入到工程中&#xff08;assets&#xff09;。 三…

Vue - 实现文件导出文件保存下载

1 文件导出&#xff1a;使用XLSX插件 需求背景&#xff1a;纯前端导出&#xff0c;如 在前端页面勾选部分表格数据&#xff0c;点击"导出"按钮导出Excel文件。 实现思路&#xff1a; 1.通过XLSX插件的 XLSX.utils.book_new()方法&#xff0c;创建excel工作蒲对象wb…

基于YOLOv7算法的高精度实时行人打电话检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时行人打电话检测系统可用于日常生活中检测与定位手机&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训练数据…

2023年度总结:技术旅程的杨帆远航⛵

文章目录 职业规划与心灵成长 ❤️‍&#x1f525;我的最大收获与成长 &#x1f4aa;新年Flag &#x1f6a9;我的技术发展规划 ⌛对技术行业的深度思考 &#x1f914;祝愿 &#x1f307; 2023 年对我来说是一个充实而令人难以忘怀的一年。这一年&#xff0c;我在CSDN上发表了 1…

3D视觉-激光三角测量法的分类

按照入射激光光束和被测物体表面法线的角度关系&#xff0c;一般分为直射式和斜射式两种方式。 1&#xff09;直射式测量 如图所示&#xff0c;激光器发出的光线&#xff0c;经会聚透镜聚焦后垂直入射到被测物体表面上&#xff0c;物体移动或者其表面变化&#xff0c;导致入射…

网络安全专家常用的12个操作系统

文章目录 前言一、什么是网络安全专家常用的OS和工具二、漏洞赏金猎人常用操作系统Kali LinuxParrot OSBlackArch Linux 三、恶意软件分析和逆向工程操作系统REMnux OSFlare-VM &#xff08;工具&#xff09; 四、OSINT和信息采集操作系统CSI LinuxTsurugi Linux 五、事件响应和…

PulseGAN

研究背景 远程光电容积描记术 (rPPG) 是一种非接触式技术&#xff0c;用于测量面部视频中的心脏信号。健康监测和情绪识别等许多领域都迫切需要高质量的 rPPG 脉冲信号。然而&#xff0c;由于脉搏信号不准确的限制&#xff0c;现有的大多数rPPG方法只能用于获取平均心率&#…

云上攻防--云服务对象存储(域名接管)弹性计算(元数据泄露)

云上攻防–云服务&&对象存储(域名接管)&&弹性计算(元数据泄露) 目录标题 云上攻防--云服务&&对象存储(域名接管)&&弹性计算(元数据泄露)对象存储权限配置错误域名接管AK/SK泄漏&#xff1a; 弹性计算元数据泄露加固措施 对象存储 各个厂商对于…

第6章 网页布局

学习目标 熟悉网页布局&#xff0c;能够说明DIVCSS布局的含义。 掌握元素的浮动属性&#xff0c;能够为元素添加和清除浮动。 熟悉overflow属性的用法&#xff0c;能够设置不同的内容溢出状态。 掌握元素的定位属性&#xff0c;能够设置不同的定位模式。 了解元素的类型&am…

外汇天眼:Valdas Dapkus和Tradewale因零售外汇欺诈计划被判支付280万美元

美国衍生品市场监管机构商品期货交易委员会&#xff08;CFTC&#xff09;宣布&#xff0c;美国新泽西地区法院于11月28日发布了对位于伊利诺伊州的Valdas Dapkus的最终裁定默认令。5月4日&#xff0c;法院对Dapkus控制的两家实体——Tradewale LLC和Tradewale Managed Fund发布…

自动化测试po模式是什么?自动化测试po分层如何实现?

一、什么是PO模式 全称&#xff1a;page object model 简称&#xff1a;POM/PO PO模式最核心的思想是分层&#xff0c;实现松耦合&#xff01;实现脚本重复使用&#xff0c;实现脚本易维护性&#xff01; 主要分三层&#xff1a; 1.基础层BasePage&#xff1a;封装一些最基…
最新文章