C++-带你初步走进继承(1)

1.继承的概念及定义

1.1继承的概念

继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段,它允许程序员在
持原有类特性的基础上进行扩展 ,增加功能,这样产生新的类,称派生类。继承 呈现了面向对象
程序设计的层次结构 ,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,
承是类设计层次的复用。
大家都知道c++的三大特性就是:面向对象,继承,多态。那么继承最重要的特点就是代码的复用。接下来我来带大家了解一下继承的概念。
下面我写了三个类,Student类和Teacher类都继承了Person类,当我们调用监视窗口可以看到,Person类里面的成员变量和成员函数在Student类和Teacher类中都有,并且Student类和Teacher类还多了自己的成员变量。
class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "xxx";
	int _age = 18;
};

class Student : public Person
{
protected:
	int _stuid; // 学号
};

class Teacher : public Person
{
protected:
	int _jobid; // 工号
};

int main()
{
	Student s;
	s.Print();
	Teacher t;
	t.Print();
	return 0;
}

1.2 继承定义

1.2.1定义格式

下面我们看到 Person 是父类,也称作基类。 Teacher是子类,也称作派生类。 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。

1.2.2继承关系和访问限定符

1.2.3继承基类成员访问方式的变化

总结:
1. 基类 private 成员在派生类中无论以什么方式继承都是不可见的。这里的 不可见是指基类的私 有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面 都不能去访问它
2. 基类 private 成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected 可以看出保护成员限定符是因继承才出现的
3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min( 成员在基类的访问限定符,继承方式 ) public > protected
> private
4. 使用关键字 class 时默认的继承方式是 private ,使用 struct 时默认的继承方式是 public 不过
最好显示的写出继承方式
5. 在实际运用中一般使用都是 public 继承,几乎很少使用 protetced/private 继承 ,也不提倡
使用 protetced/private 继承,因为 protetced/private 继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

当我把Student变成保护继承之后,就会发生报错,因为Print就变成了保护函数,访问不了变量。 

 

 2.基类和派生类对象赋值转换

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 。这里有个形象的说法叫切片
或者切割。寓意把派生类中父类那部分切来赋值过去。
基类对象不能赋值给派生类对象。

3.继承中的作用域

1. 在继承体系中 基类 派生类 都有 独立的作用域
2. 子类和父类中有同名成员, 子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏, 也叫重定义。 (在子类成员函数中,可以 使用 基类 :: 基类成员 显示访问
3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
4. 注意在实际中在 继承体系里 面最好 不要定义同名的成员

我在Person类和Student类都写了一个fun函数,这两个fun函数只有参数不同,那么是构成重载吗?不是,这两个函数构成隐藏 ,为什么呢?因为两个类的作用域是独立的,而构成重载的前提是同一作用域。

 

 

如果出现基类和派生类定义了同名成员,可以使用使用 基类::基类成员 显示访问。


4.派生类的默认成员函数

6 个默认成员函数, 默认 的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类
中,这几个成员函数是如何生成的呢?
1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
3. 派生类的 operator= 必须要调用基类的 operator= 完成基类的复制。
4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
保证派生类对象先清理派生类成员再清理基类成员的顺序。
5. 派生类对象初始化先调用基类构造再调派生类构造。
6. 派生类对象析构清理先调用派生类析构再调基类的析构。
7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同 ( 这个我们后面会讲
) 。那么编译器会对析构函数名进行特殊处理,处理成 destrutor() ,所以父类析构函数不加
virtual 的情况下,子类析构函数和父类析构函数构成隐藏关系。
class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};


class Student :public Person
{
public:

protected:
	int _id;//学号
};

int main()
{
	Student s;
	return 0;
}

当我实例化一个Student的对象s时,调用了父类的构造和析构函数,这就说明了当派生类进行实例化时,会调用基类的构造函数来构造派生类中基类的成员。

 当我自己写了一个Student的构造函数,那么怎么初始化基类的成员呢?可以在初始化列表调用基类的构造函数,然后我们可以看到,是先调用了基类的构造函数,再构造派生类的成员。

那么拷贝构造和赋值重载怎么构造的呢?也是差不多的,使用基类的构造函数完成对基类成员的构造,然后使用赋值的切片,把基类的成员切过去构造。

 

那析构函数呢?析构函数需要显示调用,而且还有一个特殊处理,就是析构要先析构派生类再析构基类。因为先析构基类的话,万一派生类使用了基类的成员,而且基类已经被析构,有可能出现基类资源已经清理释放掉了,然后派生类还去访问了基类的成员,就会存在野指针的问题。所以在派生类的析构函数被调用之后,基类的析构函数会自动调用。

 

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};


class Student :public Person
{
public:
	Student(const char* name,int id)
		:_id(id)
		,Person(name)
	{
		cout << "Student()" << endl;
	}
	Student(const Student& s)
		:Person(s)
		,_id(s._id)
	{
		cout << "Student(const Student& s)" << endl;
	}
	Student& operator=(const Student& s)
	{
		cout << "Student& operator=(const Student& s)" << endl;
		if (this != &s)
		{
			_id = s._id;
			Person::operator=(s);
		}
		return *this;
	}
	~Student()
	{
		//Person::~Person();
		cout << "~Student()" << endl;
	}
protected:
	int _id;//学号
};

int main()
{
	Student s1("张三",18);
	Student s2(s1);
	Student s3 = s1;
	return 0;
}

今天的分享到这里就结束了,感谢大家的阅读!

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

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

相关文章

前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第十一章 基础界面开发 (组件封装和使用)

前言 Vue 是前端开发中非常常见的一种框架&#xff0c;它的易用性和灵活性使得它成为了很多开发者的首选。而在 Vue2 版本中&#xff0c;组件的开发也变得非常简单&#xff0c;但随着 Vue3 版本的发布&#xff0c;组件开发有了更多的特性和优化&#xff0c;为我们的业务开发带…

如何搭建一款论坛系统?简单介绍多功能论坛系统。

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 论坛系统简单介绍就是&#xff1a;跟微博类似的app系统&#xff0c;粉丝用户可以很好…

Web服务器基础

Web服务器基础 【一】前端概述 【1】HTML HTML&#xff08;超文本标记语言&#xff09;是用于创建网页结构的标记语言。它定义了网页的骨架&#xff0c;包括标题、段落、列表、链接等元素&#xff0c;但没有样式。可以将HTML视为网页的结构和内容的描述。 【2】CSS css&…

ARM体系在linux中的中断抢占

上一篇说到系统调用等异常通过向量el1_sync做处理&#xff0c;中断通过向量el1_irq做处理&#xff0c;然后gic的工作都是为中断处理服务&#xff0c;在rtos中&#xff0c;我们一般都会有中断嵌套和优先级反转的概念&#xff0c;但是在linux中&#xff0c;中断是否会被其他中断抢…

MybatisPlus创建时间不想用默认值

我们知道&#xff0c;MybatisPlus可以给一些字段设置默认值&#xff0c;比如创建时间&#xff0c;更新时间&#xff0c;分为插入时设置&#xff0c;和更新时设置。 常见的例子&#xff1a; /*** 创建时间*/ JsonFormat(shape JsonFormat.Shape.STRING, pattern"yyyy-MM…

基于Java SSM框架实现疫情防控系统项目【项目源码】计算机毕业设计

基于java的SSM框架实现疫情防控系统演示 Java技术 Java技术它是一个容易让人学会和使用的一门服务器语言。它在编程的过程当中只需要很少的知识就能建立起一个真正的交互站点。对于这个教程来说它并不需要你完全去了解这种语言&#xff0c;只要能快速融入web站点就可以&#x…

【正点原子STM32连载】 第五十二章 串口IAP实验 摘自【正点原子】APM32E103最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32E103最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第五…

探索编程世界的电影之旅

前言 计算机科学是一个充满创意和无限可能性的领域&#xff0c;而一些精彩的电影作品能够引导我们深入这个令人着迷的编程世界。在这部电影之旅中&#xff0c;我们将一同穿越虚拟世界、探索创业之路、追随时间的脚步&#xff0c;感受计算机科学的奇妙之处。 1. 《黑客帝国》 …

2024 斯坦福提供的10门免费在线课程

看到下面这些免费的课程&#xff0c;那些割韭菜的人良心不会痛嘛&#xff1f; 希望看到这篇文章的朋友们秉持开源精神&#xff0c;互助精神&#xff0c;不割韭菜。 建了一个AI交流社区&#xff0c;欢迎加入。 高质量AI社群&#xff0c;大咖云集&#xff0c;免费开放7天 计算…

unity学习(28)——登录功能

有之前注册的知识&#xff0c;登录就很容易处理了。 登陆成功返回id&#xff1a; 登录失败返回null&#xff1a; 测试同一账号不能重复登陆&#xff01;登录成功后最好可以跳到新的场景中 结果是好的&#xff0c;去服务器看一下对应部分的代码&#xff0c;可见&#xff0c;登…

浏览器,前端发版后你依旧看的是旧内容?缓存清除

浏览器页面缓存&#xff0c;需要硬性加载。硬性加载只能在f12或检查模式使用。 然后右键点击刷新

【MySQL初阶】索引

1. 索引基本概念 1.1 索引介绍 索引(index)&#xff1a;是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或者多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现。&#xff08;具体细节在MySQL进阶章节详…

提取游戏音频文件.bnk

提取游戏音频文件.bnk 什么是.bnk准备Wwise-Unpacker工具使用Wwise-Unpacker工具总结 什么是.bnk .bnk其实是一种对音频的加密方式&#xff0c;一个.bnk文件中通常包含了多个语音文件&#xff0c;一般可以使用Wwise-Unpacker来解码.bnk格式文件 准备Wwise-Unpacker工具 Wwis…

威尔金森功分器基本原理学习笔记

威尔金森功分器基本原理 威尔金森功率分配器的功能是将输入信号等分或不等分的分配到各个输出端口&#xff0c;并保持相同输出相位。环形器虽然有类似功能&#xff0c;但威尔金森功率分配器在应用上具有更宽的带宽。微带形功分器的电路结构如图所示&#xff0c;其中&#xff0…

Mysql如何优化数据查询方案

mysql做读写分离 读写分离是提高mysql并发的首选方案。 Mysql主从复制的原理 mysql的主从复制依赖于binlog&#xff0c;也就是记录mysql上的所有变化并以二进制的形式保存在磁盘上&#xff0c;复制的过程就是将binlog中的数据从主库传输到从库上。 主从复制过程详细分为3个阶段…

探索AI视频生成新纪元:文生视频Sora VS RunwayML、Pika及StableVideo——谁将引领未来

探索AI视频生成新纪元&#xff1a;文生视频Sora VS RunwayML、Pika及StableVideo——谁将引领未来 sora文生视频&#xff0c;探索AI视频生成新纪元 由于在AI生成视频的时长上成功突破到一分钟&#xff0c;再加上演示视频的高度逼真和高质量&#xff0c;Sora立刻引起了轰动。在S…

vtkPolyData 生成轮廓线

PolyData 的轮廓用法实战 #include <vtkActor.h> #include <vtkCutter.h> #include <vtkMath.h> #include <vtkNamedColors.h> #include <vtkNew.h> #include <vtkPlane.h> #include <vtkPolyDataMapper.h> #include <vtkPropert…

MybatisPlus多表联查-分页关联查询+根据id获取多表联查后的单行数据

分页关联查询 需求分析 有两张表w以及d&#xff0c;需要w的一些字段以及d的一些字段在前端显示 此时就需要用到关联查询&#xff0c;查询到的数据放入视图类&#xff0c;显示在前端 项目结构 视图类 package com.wedu.modules.tain.entity.vo;import lombok.Data;import ja…

使用智能电销机器人,拓客效果更佳!

现在很多的企业做销售都离不开电话营销&#xff0c;它是一种能够直接帮助企业获取更多利润的营销模式&#xff0c;目前被各大行业所采用。 znyx222 了解探讨 电话营销是一个压力很大的职业&#xff0c;新员工培养难度大、老员工又不好维护&#xff0c;会有情绪问题出现等&…

WPF中样式

WPF中样式&#xff1a;类似于winform中控件的属性 <Grid><!-- Button属性 字体大小 字体颜色 内容 控件宽 高 --><Button FontSize"20" Foreground"Blue" Content"Hello" Width"100" Height"40"/></G…