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();  //testAreturn 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 testAreturn 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类中的xcout << c.x << endl;    //1//获取c类中继承与A类的xcout << c.A::x << endl; //2//获取c类中继承与B类的xcout << c.B::x << endl; //3return 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与A2B类多继承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;  //tomcout << yt.Tuo::name << endl;   //jerrycout << &(yt.Yang::name) << endl;   //0x61fe2ccout << &(yt.Tuo::name) << endl;    //0x61fe5ereturn 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;  //tomcout << yt.Tuo::name << endl;   //tomcout << &(yt.Yang::name) << endl;   //0x61fe5ccout << &(yt.Tuo::name) << endl;    //0x61fe5creturn 0;
}

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

在这里插入图片描述

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

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

相关文章

菜鸟网络Java实习一面面经

自我介绍&#xff0c;做过的项目 巴拉巴拉 你项目中用到redis&#xff0c;可以介绍一下为什么使用它吗&#xff1f; 基于内存操作&#xff0c;内存读写速度快。 支持多种数据类型&#xff0c;包括String、Hash、List、Set、ZSet等。 支持持久化。Redis支持RDB和AOF两种持久…

K8S异常处理

一、概述 1、k8s有时候会报错The connection to the server ip:6443 was refused - did you specify the right host or port &#xff0c;本文档提供几种可能产生该报错的原因和排障思路。 二、发现问题 使用任意Kubectl 命令会报错&#xff1a;The connection to the serv…

JVM GC 算法原理概述

对于JVM的垃圾收集&#xff08;GC&#xff09;&#xff0c;这是一个作为Java开发者必须了解的内容&#xff0c;那么&#xff0c;我们需要去了解哪些内容呢&#xff0c;其实&#xff0c;GC主要是解决下面的三个问题&#xff1a; 哪些内存需要回收&#xff1f; 什么时候回收&…

透过许战海矩阵洞察安记食品增长战略

引言&#xff1a;安记食品如果想实施增长战略&#xff0c;建议深耕招牌产品,走向全国市场,目前招牌产品咖哩和复合调味粉市场空间没有被全面释放出来,需要科学的产品战略作为支撑。安记食品选择功能性产品方向是正确的,但“功能性”需要一个大品类作为载体,牛奶,饮料是最大的载…

SpringBoot - Maven 打包合并一个胖 JAR 以及主项目 JAR 依赖 JAR 分离打包解决方案

问题描述 <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.1.18.RELEASE</version><configuration><!--<classifier>exec</classifier>--…

产品经理学习-怎么写PRD文档

目录 瀑布流方法论介绍 产品需求文档&#xff08;PRD&#xff09;介绍 产品需求文档的基本要素 撰写产品需求文档 优先产品需求文档的特点 其他相关文档 瀑布流方法论介绍 瀑布流模型是一种项目的开发和管理的方法论&#xff0c;是敏捷的开发管理方式相对应的另一种方法…

Google机器人团队获ICRA 2023 机器人学习方向最佳论文奖:机器人实体控制的大语言模型程序

这篇论文主要讨论了大型语言模型&#xff08;LLM&#xff09;在机器人控制方面的应用。作者们指出&#xff0c;尽管LLM在理解和生成自然语言方面表现出色&#xff0c;但其在实际应用中&#xff0c;如机器人控制等领域的应用仍然有限。因此&#xff0c;他们提出了一种新的方法&a…

通过栈将中缀表达式转换为等价的后缀表达式

为什么要从中缀表达式转换为等价的后缀表达式&#xff1f; →使后缀表达式包含运算符优先级的信息&#xff0c;方便计算机能理解进行运算。 什么是中缀表达式&#xff1f; →中缀表达式虽然是人类看得懂的简单算术形式&#xff0c;但对计算机来说反而复杂难以理解 什么是后缀表…

【头歌实训】PySpark Streaming 入门

文章目录 第1关&#xff1a;SparkStreaming 基础 与 套接字流任务描述相关知识Spark Streaming 简介Python 与 Spark StreamingPython Spark Streaming APISpark Streaming 初体验&#xff08;套接字流&#xff09; 编程要求测试说明答案代码 第2关&#xff1a;文件流任务描述相…

<JavaEE> TCP 的通信机制(三) -- 滑动窗口

目录 TCP的通信机制的核心特性 四、滑动窗口 1&#xff09;什么是滑动窗口&#xff1f; 2&#xff09;滑动窗口的作用是什么&#xff1f; 3&#xff09;批量传输出现丢包如何处理&#xff1f; 1> 接收端ACK丢包 2> 发送端数据包丢包 4&#xff09;适用性 TCP的通…

Mysql 容易忘的 sql 指令总结

目录 一、操作数据库的基本指令 二、查询语句的指令 1、基本查询语句 2、模糊查询 3、分支查询 4、 分组查询 5、分组查询 6、基本查询总结&#xff1a; 7、子查询 8、连接查询 三、MySQL中的常用函数 1、时间函数 2、字符串函数 3、聚合函数 4、运算函数 四、表…

【elk-day01】es和kibana搭建及验证---Mac-Docker

Mac系统使用Docker下载搭建和验证eskibana Docker下载安装es安装es验证kibana安装kibana验证 Docker下载安装 Docker Desktop官网安装下载地址 说明一下为什么要安装desktop版本的docker&#xff0c;因为docker作为工具使用&#xff0c;我们需要的是开箱即用&#xff0c;没有必…

QT中的信号与槽的讲解

文章目录 信号及其特点槽及其特点代码演示标准信号与标准槽函数方式一方式二 自定义信号和槽connect()函数信号和槽函数存在函数重载的情况下Qt的信号槽机制注意事项 信号及其特点 信号&#xff1a;是一种特殊的函数&#xff0c;又称信号函数&#xff0c;俗称信号&#xff0c;…

2023年新一代开发者工具 Vue ,正式开源!

以下文章来源于前端充电宝 &#xff0c;作者CUGGZ 近日&#xff0c;Vue 新一代开发者工具&#xff08;DevTools&#xff09;正式开源&#xff01;Vue DevTools 是一个旨在增强 Vue 开发人员体验的工具&#xff0c;它提供了一些功能来帮助开发者更好地了解 Vue 应用。下面就来看…

第九部分 图论

目录 例 相关概念 握手定理 例1 图的度数列 例 无向图的连通性 无向图的连通度 例2 例3 有向图D如图所示&#xff0c;求 A, A2, A3, A4&#xff0c;并回答诸问题&#xff1a; 中间有几章这里没有写&#xff0c;感兴趣可以自己去学&#xff0c;组合数学跟高中差不多&#xff0c…

记录汇川:MODBUS TCP-梯形图

H5U的MODBUS通信不需要编写程序&#xff0c;通过组态MODBUS通信配置表&#xff0c;实现数据通信。 Modbus-TCP 主站即Modbus-TCP客户端&#xff0c;通过Modbus-TCP配置&#xff0c;可最多支持同时与31个 Modbus-TCP服务器&#xff08;从站&#xff09;进行通讯。 …

【51单片机系列】DS18B20温度传感器模块

本文是关于温度传感器的相关内容。 文章目录 一、 DS18B20数字温度传感器介绍1.1、 DS18B20温度传感器的特点1.2、DA18B20内部结构1.3、 DS18B20的温度转换规则1.4、 DS18B20的ROM指令表1.6、 计算温度1.7、 读写时序 二、DS18B20使用示例 一、 DS18B20数字温度传感器介绍 DS1…

CloneNotSupportedException的解决方案 + Object的clone方法分析

CloneNotSupportedException的解决方案 引入问题&#xff1a; 在一次测试clone方法时&#xff0c;D类Override了Object类的clone方法 public class D {private Integer A1;private Integer A2;public D() {}public D(Integer a1, Integer a2 {A1 a1;A2 a2;}Overrideprotec…

Vlan的封装模式和端口讲解(Access、Trunk、Hypbrid端口)

目录 Vlan的封装模式 ISL协议 802.1Q协议 二层接口类型 Access接口 Trunk接口 Hybrid接口 不同Vlan之间的通信 Vlan的作用&#xff08;Vlan工作于OSI参考模型的第二层&#xff09; Vlan&#xff08;Virtual Local Area Network&#xff09;虚拟局域网&#xff0c;将一个…

公司电脑文件加密系统——防止内部核心文件数据 | 资料外泄,自动智能透明加密保护

一套从源头上保障企业电脑数据安全和电脑使用安全的加密软件。天锐绿盾加密软件包含了表格数据加密、图纸加密、文档文件加密、内网文件加密流转、密级管控、电脑离线管理、文件外发管理、灵活的审批流程、工作模式切换、服务器白名单等功能。天锐绿盾加密系统全面覆盖Mac、Win…