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

【继承】讲解

访问控制

传递下去可以一共分为四个特性

  1. 公有
  2. 保护
  3. 私有
  4. 存在但不可见
    虽然它们各自的特性不同,能不能使用也另说,但是在建立类对象的时候,系统都会申请相应的内存,也就是说,无论它们能不能用,它们都存在。

公有继承

在这里插入图片描述

  1. 基类的私有数据成员存在但在派生类里不可见
    即不可直接使用:
    在这里插入图片描述
    在这里插入图片描述
    但可以间接利用公有成员函数访问:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

私有继承

在这里插入图片描述

  1. 基类的公有和保护变为派生类的私有,可以在派生里边直接用,但不能在主函数里边用,就和派生类原有的私有数据成员同样的特性。基类的私有在派生类里边存在但不可见,但是可以和上面的方法一样用函数间接使用。
    在这里插入图片描述

保护继承

  1. 保护数据成员是专门为基类和派生类之间的层次关系准备的,对外界来说,它和私有数据成员没什么区别。
    在基类与派生类之间调用保护类数据成员时,保护类数据成员和公有数据成员用法无异;但在主函数里,保护类数据成员不可见,而公有类数据成员可见,二者有异。
    在这里插入图片描述

重名成员(不难,随便看看就ok)

屏蔽和访问

1.重名数据成员

class  base{ public :int  a ,  b ;  } ;
class  derived : public  base{ public :  int  b ,  c ; } ;
void  f ()
{ derived  d ;d . a = 1 ;d . base :: b = 2 ;//作用域控制符访问d . b = 3 ;d . c = 4 ;
};

2.重名成员函数

#include<iostream.h>
class A
{ public:	  int a1, a2 ;A( int i1=0, int i2=0 ) { a1 = i1; a2 = i2; }void print() { cout << "a1=" << a1 << '\t' << "a2=" << a2 << endl ; }
};
class B : public A
{ public:	int b1, b2 ;B( int j1=1, int j2=1 ) { b1 = j1; b2 = j2; }void print()		//定义同名函数{ cout << "b1=" << b1 << '\t' << "b2=" << b2 << endl ; }void printAB(){ A::print() ;		//派生类对象调用基类版本同名成员函数print() ;		//派生类对象调用自身的成员函数}
};
void main()
{ B  b ;        b.A::print();	b.printAB();  }

继承过程中的静态成员

记住共享,无论是基类还是派生类只要它们的数据成员的名字相同,它们的数据成员的大小的改变就是同时的,数据是共享的,尽管不是同一个类里面的数据成员

#include<iostream>
using namespace std;
class B
{
public:static void Add() { i++; }//静态成员函数的功能主要是改变静态数据成员的大小static int i;//静态数据成员void out() { cout << "static i=" << i << endl; }
};
int B::i = 0;//初始化必须在类外
class D : private B
{
public:void f(){i = 5;//私有继承,i变成了类D的私有数据成员Add();//D的成员函数B::i++;//改变的是类B的公有数据成员,参考数据成员变量B::Add();//B的成员函数}
}; 
void main()
{B x;  D y;x.Add();//x.i=1;x.out();//y.f();//y.i=6;y.B::i=8//访问静态数据成员的两种不同的方式cout << "static i=" << ++(B::i) << endl;//用作用域符访问静态数据成员//8//9cout << "static i=" << x.i << endl;//用类对象访问静态数据成员//8//9//cout<<"static i="<<y.i<<endl;//错误,i是类D的私有数据成员,在主函数里边不可访问
}

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

基类的初始化

派生类继承了基类中除构造函数和析构函数之外的所有成员
基类的构造函数和析构函数不能被派生类所继承,派生类需要定义自己的构造函数和析构函数
在这里插入图片描述
由于在继承的过程中,基类的构造函数不会被继承,所以为了初始化基类的数据,C++提供了一种机制,可以通过在派生类对象初始化的时候利用初始化式调用基类的构造函数来进行对基类数据的初始化。
对于基类和派生类构造函数的执行顺序,不依照初始化式来进行,而是依靠继承路径来执行。
执行的顺序一般为,基类,对象数据成员,派生类本身。
直接基类和间接基类:
父类被称为子类的直接基类
父类的父类或更高层次的父类被称为这个子类的间接基类

#include<iostream>
#include<cstring>
using namespace std;
class people
{
public:char name[50];people(char* p) { strcpy(name, p); cout << "people " << p << " init" << endl; }
};
class student : virtual public people
{
public:char stunumber[10];student(char* p, char* q) : people(p){ strcpy(stunumber, q); cout << "student " << p << " " << q << " init" << endl; }
};
class teacher : virtual public people
{
public:char ternumber[10];teacher(char* p, char* r) : people(p){ strcpy(ternumber, r); cout << "teacher " << p << " " << r << " init" << endl; }
};
class teacher_student : public student,public teacher
{
public:teacher_student(char* p, char* q, char* r): people(p),student(p,q),teacher(p,r){ cout << "teacher_student " << p << " " << q << " " << r << " init" << endl; }
};
int main()
{int i;cin >> i;if (i == 0) return 0;people p1("ZhangSan");student s1("LiSi", "01247012");teacher t1("WangWu", "83005");teacher_student ts1("ZhaoLiu", "01147011", "92002");return 0;
}

继承的应用实例

课本上主要举了圆柱体,圆,点之间的继承关系,还顺便把继承关系和包含关系比较了一把。下面就通过一个例题看吧:

class Base1
{ public :
Base1( int i )
{ cout << “调用基类Base1的构造函数:<< i << endl; }
int i;
};
class Base2
{ public:
Base2( int j )
{ cout << “调用基类Base2的构造函数:<< j << endl; }
};
class A : public Base1, public Base2
{ public :
A( int a,int b,int c,int d):Base2(b),Base1(c),b2(a),b1(d)
{ cout << “调用派生类A的构造函数:<< a+b+c+d << endl; }
private :
Base1 b1;
Base2 b2;
};
//
看冒号后边的继承顺序,并且按照先构造基类,
然后派生类数据成员,最后派生类的顺序。
先构造Base1,再构造Base2,然后对于类的成员,
就可以接着按照初始化的顺序来依次构造,(这里其实这两个成员用的就是包含的形式,
在A类里边包含了Base1,和Base2的类对象,
因此在外界访问的时候
(如果满足条件可以访问的话)
就得写成obj.b1.i)
//类的继承和包含最后实现的效果是一样的,
只是访问形式和数据的存储形式与等级不同
int main()
{ A obj( 1, 2, 3, 4 );
}

多继承

一个派生类仅有一个直接基类,称为单继承;
一个类可以从多个基类里边派生出来,即一个类有多个直接基类(例如一个物品具有多种特征),称为多继承。
在这里插入图片描述

多继承的派生类构造和访问

像上面的例题讲的一样的问题,就是由于这个派生类同时由许多基类产生,换句话说这个小孩有许多直接遗产需要继承。
然后就需要构造,构造的顺序是,先基类,(同时有很多基类的话就按照基类继承的顺序依次进行),然后派生类的数据成员这儿有点道道。。。见下方代码),最后是派生类本身(有时候要要注意虚继承的构造函数的结果)

#include<iostream>
using namespace std;
class D
{
public:D(){cout << "constructed" << endl;}~D(){cout << "deleted" << endl;}
};
class Base1 :public D
{
public:Base1(int i){cout << "调用基类Base1的构造函数:" << endl;}~Base1(){cout << "调用基类Base1的析构函数" << endl;}int i;
};
class Base2 :  public D
{
public:Base2(int j){cout << "调用基类Base2的构造函数:" << endl;}~Base2(){cout << "调用基类Base2的析构函数" << endl;}
};
class A : public Base1, public Base2
{
public:A(int a, int b, int c, int d) :Base2(b), Base1(c), b2(a), b1(d)//前两个基类的构造顺序是看public继承时候的特性,由于上面写的是先继承Base1,后继承Base2,所以结果是先构造Base1,再构造Base2;紧接着是派生类的两个类类型的数据成员,由于这两个类数据成员在private里的顺序,也就是作为该派生类数据成员的顺序,是先Base2,再Base1,因此先构造b1,再构造b2,也就是先Base2,再Base1{cout << "调用派生类A的构造函数:" << a + b + c + d << endl;}~A(){cout << "调用派生类A的析构函数" << endl;
}
private:Base2 b1;Base1 b2;
};
int main()
{A obj(1, 2, 3, 4);
}

在这里插入图片描述

虚继承

一个类不能被多次说明为一个派生类的直接基类,但可以不止一次地成为间接基类。
1.非虚继承
直接基类是上一级,间接基类是源头的那一级。
针对,D继承B1,B2,同时B1,B2又分别继承自B,由于是非虚继承,就导致在D类对象中会有两个继承B类的成员副本(静态成员函数就只有一个成员副本,因为它的共享特性),B是D的非虚基类。
而我们的本意是希望在派生类D的对象中只有一个B的成员副本,因为毕竟就只想继承一次间接基类B的成员副本,但是由于继承顺序的关系,先B1再B,先B2再B,这样就会执行两次间接基类B的构造函数。比如,在我们想调用B类的成员函数时,若D a,a.getdata();由于有B1从B类中继承过来的成员函数——getdata(),也有B2从B类中继承过来的成员函数——getdata(),直接像上面这样调用的话,会产生二义性,因此我们需要加上作用域。(转下文)
为了不两次调用非虚基类的构造函数,为了避免访问时产生的二义性,可以用作用域进行显示转换,但是很麻烦,所以就直接使用虚继承。
2.虚继承
只对基类对象的数据初始化一次,就要把B1和B2对B的继承说明为虚继承,在继承路径的时候,在类继承的关键字之前加上virtual。
也就是说B1,B2类虚继承B类,B是它们的虚基类。
因此一个类在类体系中可以作为虚基类或非虚基类,这取决于派生类对它的继承方式,而与基类本身的定义方式无关。因此,为了建立唯一的间接基类版本,应该声明派生类为虚继承基类,而不是声明间接基类为虚基类
因为如果直接声明间接基类为虚基类,也就是直接定义的话,这样根本就不知道到底是你哪个派生类,什么样的继承方式究竟是怎样的,对于消除二义性没有什么意思。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧随其后的基类起作用需要注意的是在第一级继承时就要将共同基类设置为虚基类。

#include<iostream>
using namespace std;
class a
{
public:a(int p=5,int q=6){cout << "a" << endl;a1 = q;}int a1;
};
class b : virtual public a
{
public:b(int m=2,int n=3){cout << 'b' << endl;b1 = n;}int b1;
};
class c : public b 
{
public:c(int x=0,int y=1,int z=10):b(1,x),a(1,y){n = z;}int n;
};
int main()
{c c1;cout << c1.n << endl << c1.a1 << endl << c1.b1 << endl;return 0;
}
结果是
a b 10 1 0
//c(int x=0,int y=1,int z=10):b(x),a(y)只改初始化的这一处结果是a b 10 6 3

下方这两处的virtual也就只能减少一次在基类构造的次数,对于派生类的类数据成员构造的时候,并不会减少间接基类的构造。

#include<iostream>
using namespace std;
class D
{
public:D(){cout << "constructed" << endl;}~D(){cout << "deleted" << endl;}
};
class Base1 : virtual public D//
{
public:Base1(int i){cout << "调用基类Base1的构造函数:" << endl;}~Base1(){cout << "调用基类Base1的析构函数" << endl;}int i;
};
class Base2 : virtual public D//
{
public:Base2(int j){cout << "调用基类Base2的构造函数:" << endl;}~Base2(){cout << "调用基类Base2的析构函数" << endl;}
};
class A : public Base1, public Base2
{
public:A(int a, int b, int c, int d) :Base2(b), Base1(c), b2(a), b1(d){cout << "调用派生类A的构造函数:" << a + b + c + d << endl;}~A(){cout << "调用派生类A的析构函数" << endl;
}
private:Base2 b1;Base1 b2;
};
int main()
{A obj(1, 2, 3, 4);
}

在这里插入图片描述

相关文章:

【继承】讲解

访问控制 传递下去可以一共分为四个特性 公有保护私有存在但不可见 虽然它们各自的特性不同&#xff0c;能不能使用也另说&#xff0c;但是在建立类对象的时候&#xff0c;系统都会申请相应的内存&#xff0c;也就是说&#xff0c;无论它们能不能用&#xff0c;它们都存在。 …...

无人机之低空管控技术

无人机的低空管控技术是对低空飞行活动进行管理和控制的一系列措施和技术的总称&#xff0c;旨在确保低空飞行活动的安全、有序和高效。 一、主要技术手段 雷达系统监测 原理&#xff1a;雷达是利用电磁波探测目标的电子设备&#xff0c;通过发射电磁波对目标进行照射并接收…...

探索 DevOps:从概念到实践

引言 在现代软件开发的世界中,DevOps 已成为一个热门词汇。它不仅改变了开发和运维的合作方式,还显著提升了软件交付的速度和质量。那么,究竟什么是 DevOps?它的定义和目标是什么?本文将为你详细解释 DevOps 的基本概念,并通过代码示例和图片帮助你更好地理解这一重要的…...

联通国际云视频:高清、稳定、易用的云端会议平台

一、产品概述 中国联通国际公司推出的云视频产品&#xff0c;是一款基于先进云计算技术的云会议架构平台。它旨在为用户提供高品质、方便快捷、简单易用、灵活多变、稳定可靠的视频通讯解决方案&#xff0c;满足用户随时随地高效沟通的需求。 二、主要功能 音视频及数据共享 …...

表达式求值(2020cspj)

题目描述 给定一个只包含加法和乘法的算术表达式&#xff0c;请你编程计算表达式的值。 输入格式 一行&#xff0c;为需要你计算的表达式&#xff0c;表达式中只包含数字、加法运算符 和乘法运算符 *&#xff0c;且没有括号&#xff0c;所有参与运算的数字均为 0 到 231−1…...

算法的学习笔记—数组中只出现一次的数字(牛客JZ56)

&#x1f600;前言 在数组中寻找只出现一次的两个数字是一道经典的问题&#xff0c;通常可以通过位运算来有效解决。本文将详细介绍这一问题的解法&#xff0c;深入解析其背后的思路。 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 &#x1f970;数组中只出现一次的数字…...

《Pyhon入门:07 map与filter函数的常用用法》

Pyhon入门之map与filter函数常用用法 一、 map函数的常用用法1. 基本用法2. 使用lambda表达式3. 多个可迭代对象4. 使用自定义函数5. 返回迭代器6. 与filter函数结合使用 二、 filter函数的常用用法 一、 map函数的常用用法 1. 基本用法 map()函数是Python内置的一个函数&…...

基于vue框架的的高校消防设施管理系统06y99(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;设备分类,设备信息,维修人员,报修信息,维修进度,院系,消防知识,培训记录,培训信息,备件信息,备件申请,派发信息,采购信息 开题报告内容 基于Vue框架的高校消防设施管理系统开题报告 一、项目背景与意义 随着高校规模的不断扩大和校园建…...

ffmpeg视频滤镜:定向模糊-dblur

滤镜简述 dblur 官网链接 > https://ffmpeg.org/ffmpeg-filters.html#dblur 有一个模糊滤镜&#xff0c;我试了一下&#xff0c;没有感觉到它的特殊之处, 这里简单介绍一下。 滤镜使用 滤镜的参数 angle <float> ..FV.....T. set angle (from 0 t…...

【数据结构初阶】二叉树---堆

二叉树-堆的实现 一、树的概念&#xff08;什么是树&#xff09;二、二叉树的概念及结构2.1 二叉树的概念2.2 二叉树的性质2.3 二叉树存储结构 三、二叉树的顺序结构3.1 堆的概念及结构3.2 堆的向下调整算法3.3堆的创建 四、堆的代码实现4.1 堆的初始化4.2 堆的销毁4.3 堆的插入…...

Lucas带你手撕机器学习——决策树

一、决策树简介 决策树是一种基本的分类与回归方法&#xff0c;它通过树状结构对数据进行分类或预测。每个内部节点代表一个特征&#xff08;属性&#xff09;&#xff0c;每个分支代表特征的一个可能值&#xff0c;而每个叶子节点代表一个分类或预测值。由于其直观和易于理解…...

OpenIPC开源FPV之Ardupilot配置

OpenIPC开源FPV之Ardupilot配置 1. 源由2. 问题3. 分析3.1 MAVLINK_MSG_ID_RAW_IMU3.2 MAVLINK_MSG_ID_SYS_STATUS3.3 MAVLINK_MSG_ID_BATTERY_STATUS3.4 MAVLINK_MSG_ID_RC_CHANNELS_RAW3.5 MAVLINK_MSG_ID_GPS_RAW_INT3.6 MAVLINK_MSG_ID_VFR_HUD3.7 MAVLINK_MSG_ID_GLOBAL_P…...

合并数组的两种常用方法比较

在 JavaScript 中&#xff0c;合并数组的两种常用方法是使用扩展运算符 (...) 和使用 push 方法。 使用扩展运算符 this.items [...this.items, ...data.items]; 优点&#xff1a; 易于理解&#xff1a;使用扩展运算符的语法非常直观&#xff0c;表达了“将两个数组合并成一个…...

qt 下载安装

1. 官网地址 https://www.qt.io/ 2. 下载 使用邮箱注册账号&#xff0c;登录&#xff0c;后边安装时也用的到 登录后&#xff1a; 这里需要电话号验证&#xff0c;电话号需要正确的&#xff0c;其他随便填&#xff0c;电话号中国区前需要86&#xff0c; 验证后自动下载 …...

Oracle SQL Developer 同时打开多个table的设置

Oracle SQL Developer 同时打开多个table的设置 工具 》 首选项 》数据库 》对象查看器&#xff0c;勾选 “自动冻结对象查看器窗口”...

NVIDIA发布Nemotron-70B-Instruct,超越GPT-4o和Claude 3.5的AI模型

一、Nemotron-70B-Instruct 是什么 Nemotron-70B-Instruct 是由 NVIDIA 基于 Meta 的 Llama 3.1-70B 模型开发的先进大语言模型&#xff08;LLM&#xff09;。该模型采用了新颖的神经架构搜索&#xff08;Neural Architecture Search&#xff0c;NAS&#xff09;方法和知识蒸馏…...

死锁(Deadlock)C#

在多线程编程中&#xff0c;死锁&#xff08;Deadlock&#xff09;是一种非常常见的问题&#xff0c;通常发生在两个或多个线程相互等待对方持有的锁&#xff0c;导致它们都无法继续执行。要避免死锁&#xff0c;需要了解死锁的四个必要条件以及相应的解决策略。 死锁的形成 …...

前端-基础CSS 知识总结

1.书写位置:title 标签下方添加 style 双标签,style 标签里面书写 CSS 代码。 <title>CSS 初体验</title> <style>/* 选择器 { } */p {/* CSS 属性 */color: red;} </style><p>体验 CSS</p> <link rel="stylesheet" href=…...

最新版本jdbcutils集成log4j做详细sql日志、自动释放连接...等

maven坐标 <!-- MySQL 8 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version></dependency><!-- Druid连接池 --><dependency><groupId&…...

jQuery快速填充非form数据

jQuery快速填充非form数据 先看看jQuery根据name填充form表单数据 <!DOCTYPE html> <html><head><script src"https://code.jquery.com/jquery-3.6.0.min.js"></script> </head><body><form id"myForm">…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...