【C++干货铺】继承后的多态 | 抽象类

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

多态的概念

多态的定义和实现

多态的定义条件

虚函数

虚函数的重写

特殊情况

协变(基类和派生类的虚函数返回值不同)

析构函数的重写

C++11 override 和 final关键字

重载、重写(覆盖)、重定义(隐藏)的对比

抽象类


多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 

举个栗子:很多朋友在外地上大学,回家或者去学校可能都会买火车票或者其他交通工具的票。但是作为一个大学生我们是有学生认证的大学生身份,买票有打折优惠;但是对于其他不是学生的公民来说就是普通人的身份是享受不到这个优惠的,必须全价买票;又或者对于军人来说,他们有军人的身份,军人优先买票。

因此对于买票这个行为,当普通人买票时,是全价买票学生买票时,是半价买票军人
买票
时,是优先买票


多态的定义和实现

多态的定义条件

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了
Person。Person对象买票全价,Student对象买票半价。

那么在继承中要构成多态还有两个条件

  • 必须通过基类的指针或者引用调用虚函数
  • 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 

虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

class Person {
public:
    virtual void Buy() { cout << "买票-全价" << endl;}
};

虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

注意:重写只是对函数体的内容重写而不是对整个函数重写,使用的还是基类的接口,只不过是函数体的内容变了。

class Person
{
public :
	virtual void Buy()
	{
		cout << "普通人——全价买票" << endl;
	}
};
class Student :public Person
{
public:
	virtual void Buy()
	{
		cout << "学生——半价买票" << endl;
	}
};
void Func(Person& p)
{
	p.Buy();
}
int main()
{
	Person p1;
	Student s1;
	Func(p1);
	Func(s1);
	return 0;
}

特殊情况

在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用。

class Person
{
public :
	virtual void Buy()
	{
		cout << "普通人——全价买票" << endl;
	}
};
class Student :public Person
{
public:
	virtual void Buy()
	{
		cout << "学生——半价票" << endl;
	}
	//派生类的虚函数前面可以不加virtual 但是这样并不规范,不建议这样使用
	//void Buy()
	//{
	//	cout << "学生——半价票" << endl;
	//}
};
void Func(Person& p)
{
	p.Buy();
}
int main()
{
	Person p1;
	Student s1;
	Func(p1);
	Func(s1);
	return 0;
}

虚函数的两个例外:

协变(基类和派生类的虚函数返回值不同)

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指
针或者引用,派生类虚函数返回派生类对象的指针或者引用时
,称为协变

class Person
{
public:
	virtual Person* Buy()
	{
		cout << "普通人——全价买票" << endl;
		return nullptr;
	}
};
class Student :public Person
{
public:
	virtual Student* Buy()
	{
		cout << "学生——半价票" << endl;
		return nullptr;
	}
};
void Func(Person& p)
{
	p.Buy();
}
int main()
{
	Person p1;
	Student s1;
	Func(p1);
	Func(s1);
	return 0;
}

返回值可以为其他类的指针

class A
{
public:
};
class B : public A
{
public:
};
class Person
{
public:
	virtual A* Buy()
	{
		cout << "普通人——全价买票" << endl;
		return nullptr;
	}
};
class Student :public Person
{
public:
	virtual B* Buy()
	{
		cout << "学生——半价票" << endl;
		return nullptr;
	}
};
void Func(Person& p)
{
	p.Buy();
}
int main()
{
	Person p1;
	Student s1;
	Func(p1);
	Func(s1);
	return 0;
}

析构函数的重写

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,
都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,
看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处
理,编译后析构函数的名称统一处理成destructor。

class Person
{
public :
	virtual ~Person()
	{
		cout << "~Person()" << endl;
	}
};
class Student
{
public:
	virtual ~Student()
	{
		cout << "~Student()" << endl;
	}
};
//只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
}

C++11 override 和 final关键字

从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数
名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有
得到预期结果才来debug会得不偿失,因此:C++11提供了overridefinal两个关键字,可以帮
助用户检测是否重写

final:修饰虚函数,表示该虚函数不能再被重写

class Person
{
public :
	virtual void Func()final
	{
		cout << "被final修饰" << endl;
	}
};
class Student : public Person
{
public:
	virtual void Func()
	{

	}
};

override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。 

//override
// 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
class Person
{
public:
	virtual void Func() {};
};
class Student : public Person
{
public:
	void Func ()override {};
};

重载、重写(覆盖)、重定义(隐藏)的对比


抽象类

抽象类的概念

虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类)抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。

class car
{
public :
	virtual void Drive() = 0;
};
class Benz :public car
{
public:
	virtual void Drive()
	{
		cout << "Benz-舒适" << endl;
	}
};
class BMW :public car
{
public:
	virtual void Drive()
	{
		cout << "BMW-操控" << endl;
	}
};
int main()
{
	Benz b;
	b.Drive();
	BMW m;
	m.Drive();
	return 0;
}


今天对继承之后的多态的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法。您三连的支持就是我前进的动力,感谢大家的支持!! !

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

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

相关文章

ffmpeg踩坑之手动编译报错Unrecognized option ‘preset‘及rtsp/rtmp推流

本文解决的问题记录&#xff1a; 报错1&#xff1a;Unrecognized option preset. Error splitting the argument list: Option not found 报错2&#xff1a;ERROR: x264 not found using pkg-config 报错3&#xff1a;ffmpeg: error while loading shared libraries: libavd…

【linux】Debian不能运行sudo的解决

一、问题&#xff1a; sudo: 没有找到有效的 sudoers 资源&#xff0c;退出 sudo: 初始化审计插件 sudoers_audit 出错 二、可用的方法&#xff1a; 出现 "sudo: 没有找到有效的 sudoers 资源&#xff0c;退出" 和 "sudo: 初始化审计插件 sudoers_audit 出错&q…

spring面试:一、面试题分类总览+bean线程安全问题+AOP相关问题(定义、使用步骤、编程式事务管理和声明式事务管理和声明式事务管理失效)

面试题分类总览 bean线程安全问题 单例/多例 单例&#xff08;singleton&#xff09;&#xff1a;在每个spring ioc容器中都只有一个实例。 多例&#xff08;prototype&#xff09;&#xff1a;在每个spring ioc容器中有多个实例。 默认情况下spring中的bean都是单例的。但是…

基于Java SSM框架实现智能停车场系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现智能停车场系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述…

call 和 apply:改变对象行为的秘密武器(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

TSINGSEE视频智能解决方案边缘AI智能与后端智能分析的区别与应用

视频监控与AI人工智能的结合是当今社会安全领域的重要发展趋势。随着科技的不断进步&#xff0c;视频监控系统已经不再局限于简单的录像和监视功能&#xff0c;而是开始融入人工智能技术&#xff0c;实现更加智能化的监控和安全管理。传统的监控系统往往需要人工操作来进行监控…

内网渗透测试基础——Windows PowerShell篇

内网渗透测试基础——Windows PowerShell篇 1. Windows PowerShell基础 Windows PowerShell是一种命令行外壳程序和脚本环境&#xff0c;它内置在每个受支持的Windows版本中&#xff08;Windows7、Windows Server 2008 R2及更高版本&#xff09;&#xff0c;为Windows命令行使…

讨好型人格最适合从事什么职业?

讨好型人格&#xff0c;其言行不是考虑个人&#xff0c;而是以满足对方为主&#xff0c;只要是他人的想法&#xff0c;都会尽力去满足&#xff0c;特别害怕自己做了什么事情&#xff0c;让对方产生不满的想法。遇到事情&#xff0c;也很难主动请求别人&#xff0c;总是依靠自己…

计算机组成原理-函数调用的汇编表示(call和ret指令 访问栈帧 切换栈帧 传递参数和返回值)

文章目录 call指令和ret指令高级语言的函数调用x86汇编语言的函数调用call ret指令小结其他问题 如何访问栈帧函数调用栈在内存中的位置标记栈帧范围&#xff1a;EBP ESP寄存器访问栈帧数据&#xff1a;push pop指令访问栈帧数据&#xff1a;mov指令小结 如何切换栈帧函数返回时…

APP安全测试填坑

在实习过程中&#xff0c;我接触到了一些SDL安全提测的工作。原来我是学web端渗透比较多的&#xff0c;移动端这块基本没怎么试过手&#xff0c;结果刚开始一直踩坑&#xff0c;连抓包都抓不到(&#xff34;▽&#xff34;)。 下面记录下我遇到的部分问题和解决方法&#xff0…

Python基础04-数据容器

零、文章目录 Python基础04-数据容器 1、了解字符串 &#xff08;1&#xff09;字符串的定义 字符串是 Python 中最常用的数据类型。我们一般使用引号来创建字符串。创建字符串很简单&#xff0c;只要为变量分配一个值即可。<class ‘str’>即为字符串类型。一对引号…

【C++干货铺】会搜索的二叉树(BSTree)

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 前言&#xff1a; 二叉搜索树 二叉搜索树概念 二叉搜索树操作 二叉搜索树的查找 二叉搜索树的插入 二叉搜索树元素的删除 ​二叉搜索树的实现 BSTree结点 …

人工智能导论习题集(4)

第六章&#xff1a;机器学习 题1题2题3 题1 题2 题3

大型网站架构演进过程

架构演进 大型网站的技术挑战主要来自于庞大的用户&#xff0c;高并发的访问和海量的数据&#xff0c;任何简单的业务一旦需要处理数以P计的数据和面对数以亿计的用户&#xff0c;问题就会变得很棘手。大型网站架构主要就是解决这类问题。 架构选型是根据当前业务需要来的&…

系列六、Springboot整合Spring Session

一、概述 在互联网发展的起始阶段&#xff0c;一般使用的是单服务架构&#xff0c;由于只有一台服务器&#xff08;Tomcat&#xff09;&#xff0c;所有的请求和响应都是基于这台服务器实现的&#xff0c;那么就不存在session共享的问题&#xff0c;但是在互联网发展的今天&…

SpringData自定义操作

一、JPQL和SQL 查询 package com.kuang.repositories;import com.kuang.pojo.Customer; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingR…

Datawhale聪明办法学Python(task3变量与函数)

一、课程基本结构 课程开源地址&#xff1a;课程简介 - 聪明办法学 Python 第二版 章节结构&#xff1a; Chapter 0 安装 Installation Chapter 1 启航 Getting Started Chapter 2 数据类型和操作 Data Types and Operators Chapter 3 变量与函数 Variables and Functions Ch…

NE555芯片

首先看一下NE555芯片的实物图以及电路符号&#xff0c;如下图所示。 NE555是使用很广泛且很受欢迎的芯片之一。上到航空航天火箭&#xff0c;下到电子玩具都能看到它的身影。 下图是它的内部结构图&#xff0c;可以更快的去学习并且上手使用这个芯片。最上面是3个5k的电阻&am…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

DS八大排序之冒泡排序和快速排序

前言 前两期我们已经对"插入排序"&#xff08;直接插入排序和希尔排序&#xff09; 和 "选择排序"&#xff08;直接选择排序和堆排序&#xff09;进行了详细的介绍~&#xff01;这一期我们再来详细介绍一组排序 &#xff1a;"交换排序"即耳熟能…