c++-----继承

01:继承是什么

定义

继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段,它允许程序员在 持原有类特性的基础上进行扩展 ,增加功能,这样产生新的类,称派生类。继承 呈现了面向对象 程序设计的层次结构 ,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用, 承是类设计层次的复用
简单来说,继承是实现代码复用的一种手段。

继承的语法

继承权限可以不写,使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public不过 最好显示的写出继承方式

打个比方

我们要实现一个学生类和一个老师类

class student {
	int name;					//姓名
	char Date_of_birth[32];		//出生日期
	char Origin[32];			//籍贯
	//.......

	long long School_Degree;	//学号
	long long Dormitory_number;	//宿舍号
	//........
};
class teacher {
	int name;					//姓名
	char Date_of_birth[32];		//出生日期
	char Origin[32];			//籍贯
	//.......

	char Graduation_school[32];	//毕业学校
	char posts[32];				//职位
	//........
};

可以看出老师类与学生类有很多相同的内容,如果要在两个类中都写个add函数的话,两个函数会有很多相同之处.这实在不够优雅,所以c++的祖师爷搞出来继承这套东西.

//个人类
class Person {
	int name;					//姓名
	char Date_of_birth[32];		//出生日期
	char Origin[32];			//籍贯
	//.......
};
//学生类,学生类依赖于个人类
class student : public Person
{
	long long School_Degree;	//学号
	long long Dormitory_number;	//宿舍号
	//........
};
//老师类,老师类依赖于个人类
class teacher : public Person
{
	char Graduation_school[32];	//毕业学校
	char posts[32];				//职位
	//........
};

子类中可以按照相应的权限来使用父类的内容


02.继承关系与访问限定符

3种继承关系:public, protected ,private与3种访问限定符:public, protected ,private.总共能组合出九种访问权限.

继承关系与访问限定符的关键字字符一样,但书写位置不同,含义不同.

巧记:

  1. 基类的private在派生类都是不可见的.
  2. public>protected>private,基类的非private元素取继承关系与访问限定符较小的为权限.

举个例子

class parent {
public:
	int pub;
protected:
	int pro;
private:
	int pri;
};
class child :public parent{		//以共有的方式继承
	void fun()
	{
		pub = 1;	//	public和public	->公有继承
		pro = 2;	//	public和protected	->保护继承
		//pri = 3;	//	父类为private	->在子类中不可见,访问会报错
	}
};

最常见的继承方式是公有继承

父类的私有元素是否会被子类继承?

以上段代码为例,我们来使用一下sizeof()

一个int为4字节,打印的12证明child继承到了三个父类元素,也就代表子类会继承父类元素

给父类写一个构造函数,通过内存窗口也能看到

结论:子类会继承父类的全部元素,但是父类的私有元素不可访问

03:子类与父类的赋值转换

子类可以直接给父类赋值,这个过程叫做切片,(请注意父类不可给子类复制,当然有手动重载的除外)

父类及父类的指针,父类的引用都可直接由对应的子类赋值.子类的指针可以通过父类指针强制类型转换来赋值,但是有越界的可能

例:

class Person {
	string _name;
	int _sex;
	int _age;
};
class Student : public Person {
	long long _no;
};
int main()
{
	Person p;
	Student s;
	Person* pp = &s;
	Person& tmp = s;
	Person qp = s;

    Student* ss = (Student*)&p;//有可能越界

	return 0;
}

04:继承的作用域

在继承的体系中,父类和子类有相互独立的作用域.

当子类和父类有同名函数时,会构成隐藏,请注意,隐藏只与函数名有关,与参数和返回值无关!!!!

默认调用的时子类函数,可以通过加上作用域来指定作用域

子类与父类最好不要定义重名函数


05.子类的默认成员函数

有的人死了,但他还活着!有的人活着,但他已经死了!       

                                                                                                                                      ----鲁迅

不知道大家自类和对象之后再次看到默认成员函数是什么感觉,反正我有点心肌梗塞,你先别怕,怕了也学不会其实这里的要比类和对象里的简单一些.

  1. 构造函数:调用子类的构造函数时必须要调用父类的构造函数,如果父类没有默认构造函数,那么在初始化子类时必须显式的调用父类的构造函数
  2. 子类的拷贝构造必须要调用父类的拷贝构造.而在子类的构造函数中给父类元素赋值
  3. 子类operator=函数必须调用父类的operator=完成赋值,而非直接访问父类元素
  4. 子类的析构在调用完之后会自动的去调用父类的析构,子类的析构中不需要显示调用父类的析构
  5. 子类的构造会先调用父类的构造函数
  6. 子类的析构会最后调用父类的析构函数

06.继承与友元

父类的友元不是子类的友元函数,也就是说父类友元不能直接访问子类保护和私有

class Student;
class Person
{
public:
 friend void Display(const Person& p, const Student& s);
protected:
 string _name; // 姓名
};
class Student : public Person
{
protected:
 int _stuNum; // 学号
};
void Display(const Person& p, const Student& s) {
 cout << p._name << endl;
 cout << s._stuNum << endl;     //不是子类友元,这里不能访问
}

07:父类与静态成员

在父类中定义的静态成员,当父类被继承到子类时,所有的子类都会只使用一个静态成员.

class A {
public:
	static int a;
};
class B : public A {
public:
	void fun() {
		cout << "在B中查看全局变量a,a的值为:"<< a << endl;
	}
};
class C : public A {
public:
	void fun() {
		cout << "在C中查看全局变量a,a的值为:" << a << endl;
	}
};
int A::a = 0;
int main() {
	A aa;
	B bb;
	C cc;
	cout << "A中aa的值改为0" << endl;
	bb.fun();
	cc.fun();
	aa.a = 10;
	cout << "A中aa的值改为10" << endl;
	bb.fun();
	cc.fun();
	system("pause");
	return 0;
}

08.多继承

多继承与单继承

单继承很好理解,譬如学生是一个人,,那么学生类就可以做人类类的子类,二者关系为单继承.

多继承可以理解为在学生和人类的基础之上,学生张三是一名某某游戏会员,那么在描述张三时,可以让张三继承两个类,这样一个子类对应多个父类,他们的关系为多继承.

Java是没有的多继承的,由此可见c++这门语言是一门旷世神作,c++程序员都聪明绝顶,Java语言过于局限,Java程序员好逸恶劳(手动滑稽),多继承毫无疑问是有现实意义的,譬如有些博士生既是老师又是学生,谷爱凌既是中国人又是美国人,马克思既是犹太人又是中国人(不是),如果使用多继承的话可以很好的实现一些面向对象功能,但是毫无疑问在后续使用菱形继承之类复杂继承时,出现了很多语法困难,c++早期版本也是一直在改进继承.

总之,多继承是有他独特的意义的,是值得学习的

多继承语法

语法很简单:在单继承的基础之上加个逗号,再加上第二个父类即可

菱形继承

可以看出,在Student类和Teacher类中都有Person类,进而在Assistant类中会有两份Person类,这就造成了代码冗余,因为两个Person中的数据很显然是一模一样的

ps:棱形继承要访问Person元素的话,需要在前面加上父类作用域,否则编译器分不清是在操作哪个Person

class Person
{
public :
 string _name ; // 姓名
};
class Student : public Person
{
protected :
 int _num ; //学号
};
class Teacher : public Person
{
protected :
 int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
 string _majorCourse ; // 主修课程
};
void Test ()
{
 // 这样会有二义性无法明确知道访问的是哪一个
 Assistant a ;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
 a.Student::_name = "xxx";
 a.Teacher::_name = "yyy"; }

虚拟继承

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在 Student
Teacher 的继承 Person 时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地
方去使用。
class Person
{
public :
 string _name ; // 姓名
};
class Student : virtual public Person
{
protected :
 int _num ; //学号
};
class Teacher : virtual public Person
{
protected :
 int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
 string _majorCourse ; // 主修课程
};
void Test ()
{
 Assistant a ;
 a._name = "peter"; }

虚拟继承的底层原理(vs2022编译器32位)

这是一些简单的类构成的菱形继承.

class A {
public:
 int _a;
};
// class B : public A
class B : virtual public A {
public:
 int _b;
};
// class C : public A
class C : virtual public A {
public:
 int _c;
};
class D : public B, public C {
public:
 int _d;
};
int main()
{
 D d;
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;
 return 0; }

首先是非虚函数,看以看到A存了两份,有数据冗余的情况

虚函数,看以看到A只存了一份

可以看出,虚函数通过存储指针->偏移量来找到二者共有的A的地址

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

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

相关文章

【C语言】带你完全理解指针(六)指针笔试题

目录 1. 2. 3. 4. 5. 6. 7. 8. 1. int main() {int a[5] { 1, 2, 3, 4, 5 };int* ptr (int*)(&a 1);printf("%d,%d", *(a 1), *(ptr - 1));return 0; } 【答案】 2&#xff0c;5 【解析】 定义了一个指向整数的指针ptr&#xff0c;并将其初始化为&…

FactoryMethod工厂方法模式详解

目录 模式定义实现方式简单工厂工厂方法主要优点 应用场景源码中的应用 模式定义 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。 Factory Method 使得一个类的实例化延迟到子类。 实现方式 简单工厂 以下示例非设计模式&#xff0c;仅为编码的一种规…

在centos8.5上迁移深度学习环境的时候碰到的一下问题(需要运维人员解决的)

我负责的是将开发服务器上的深度学习环境进行打包并将该环境迁移到生产服务器上&#xff0c;这些操作可以在其他博客中搜到 本文主要介绍我把环境包上传至生产服务器中的anaconda/envs/路径下&#xff0c;解压之后&#xff0c;运行测试代码时遇到的问题 IT部门是如何处理的&am…

mfc 带有复选框的ListBox

mfc 带有复选框的 ListBox 效果&#xff1a; 添加 ListBox 控件 从工具箱拖拽 ListBox 控件到窗口上&#xff0c;并设置属性&#xff1a; 包含字符串&#xff1a;true所有者描述&#xff1a;Fixed 给ListBox添加控制变量 添加完后&#xff0c;将m_list_box的类型使用CC…

Rustdesk如何编译代码实现安装后,不会在右下角出现托盘图标

环境&#xff1a; Rustdesk1.1.9 问题描述&#xff1a; Rustdesk如何编译代码实现安装后&#xff0c;不会在右下角出现托盘图标 解决方案&#xff1a; 安装后只有自定义进程图标 详细方案&#xff0c;有需要私聊

L2-1 堆宝塔分数

本题链接&#xff1a;PTA | 程序设计类实验辅助教学平台 题目&#xff1a; 样例&#xff1a; 输入 11 10 8 9 5 12 11 4 3 1 9 15 输出 4 5 思路&#xff1a; 这是一道模拟题&#xff0c;需要有耐心读题&#xff0c;跟着题目走一遍&#xff0c;就可以了。 代码详解如下&…

中霖教育:没有计量相关工作经验可以考注册计量师吗?

不可以&#xff0c;报考注册计量师需要满足相关工作年限要求&#xff0c;如果没有相关工作经验是不能报考的。 具体要求如下&#xff1a; 一级计量师; 1.取得理学类或工学类专业大学专科学历&#xff0c;工作满6年&#xff0c;其中从事计量技术工作满4年; 2.取得理学类或工…

每日OJ题_完全背包②_力扣322. 零钱兑换

目录 力扣322. 零钱兑换 问题解析 解析代码 优化代码&#xff08;滚动数组&#xff09; 力扣322. 零钱兑换 322. 零钱兑换 难度 中等 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以…

外观模式:简化复杂系统的统一接口

在面向对象的软件开发中&#xff0c;外观模式是一种常用的结构型设计模式&#xff0c;旨在为复杂的系统提供一个简化的接口。通过创建一个统一的高级接口&#xff0c;这个模式帮助客户端通过一个简单的方式与复杂的子系统交互。本文将详细介绍外观模式的定义、实现、应用场景以…

链表拓展之双向链表

前言 在前面已经总结了单链表&#xff0c;有了单链表的基础会很好理解双链表的实现&#xff0c;忘记了可以跳转——>http://t.csdnimg.cn/GFPk9 接下来就由我带着各位看官来认识今天的主角吧~ 什么是双向链表 在单链表的基础上&#xff0c;它有两个方向的链接&#xff0c;一…

加强fou循环的坑

今天遇到了一个有趣的事情&#xff0c;使用加强fou循环操作list时&#xff0c;会报错并发操作异常。 直到看了编译类&#xff0c;才发现&#xff0c;加强fou循环其实就是通过迭代器操作&#xff1a; 这里就会出现一个问题&#xff0c;迭代器在取出值时&#xff0c;就回去检测这…

分析ARP解析过程

一、实验环境 主机A和主机B连接到交换机&#xff0c;并与一台路由器互连&#xff0c;如图7.17所示&#xff0c;路由器充当网关。 图7.17 二、需求描述 查看 ARP 相关信息,熟悉在PC 和 Cisco 设备上的常用命令,设置主机A和主机B为同一个网段网关设置为路由接口地址。 三、推…

基于Python的景区票务人脸识别系统(V2.0)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

排列特征重要性(Permutation Feature Importance)

5个条件判断一件事情是否发生&#xff0c;每个条件可能性只有2种&#xff08;发生或者不发生&#xff09;&#xff0c;计算每个条件对这件事情发生的影响力。排列特征重要性模型的程序。 例一 在机器学习领域&#xff0c;排列特征重要性&#xff08;Permutation Feature Impor…

QT 串口助手 学习制作记录

QT 串口助手qt 学习制作记录 参考教程&#xff1a;​​​​​​QT初体验&#xff1a;手把手带你写一个自己的串口助手_qt设计串口助手的流程图-CSDN博客 Qt之串口编程&#xff08;添加QSerialPort模块&#xff09;_如何安装 qt串口模块教程-CSDN博客 串口调试助手&#xff1…

2.2 @SpringBootApplication

2.2 SpringBootApplication 在前文的介绍中&#xff0c;读者已经了解到SpringBootApplication注解是加在项目的启动类上的。 SpringBootApplication实际上是一个组合注解&#xff0c;定义如下&#xff1a; SpringBootConfiguration EnableAutoConfiguration ComponentScan(exc…

python-常用数据结构(2)

6、某企业为职工发放奖金:如果入职超过5年,且销售业绩超过15000元的员工,奖金比例为0.2;销售业绩超过10000元的员工,奖金比例为0.15:销售业绩超过5000元的员工,奖金比例为0.1;其他奖金比例为0.05。如果是人职不超过5年,且销售业绩超过4000的员工,奖金比例为0.045;否则为0.01。输…

使用Python模仿文件行为

在Python中&#xff0c;你可以通过文件操作函数&#xff08;如open()函数&#xff09;以及模拟输入输出流的库&#xff08;如io模块&#xff09;来模拟文件行为。下面是一些示例&#xff0c;展示了如何使用这些工具在Python中模拟文件行为。 1、问题背景 在编写一个脚本时&…

深度挖掘响应式模式的潜力,从而精准优化AI与机器学习项目的运行效能,引领技术革新潮流

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f525; 转载自热榜文章&#xff1a;探索设计模式的魅力&#xff1a;深度挖掘响应式模式的…

基于Docker构建CI/CD工具链(六)使用Apifox进行自动化测试

添加测试接口 在Spring Boot Demo项目里实现一个简单的用户管理系统的后端功能。具体需求如下&#xff1a; 实现了一个RESTful API&#xff0c;提供了以下两个接口 &#xff1a; POST请求 /users&#xff1a;用于创建新的用户。GET请求 /users&#xff1a;用于获取所有用户的列…