C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类

前言

看这篇之前,可以先看多态性与虚函数(1)⬇️

C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_74197067/article/details/138861418?spm=1001.2014.3001.5501这篇文章会接着上一篇来记录

虚析构函数

构造函数不能是虚函数,但析构函数可以是虚函数,同样的在析构函数前面加上virtual就 称该析构函数为虚析构函数,语法如下:

virtual ~类名() 

{

        函数体

}

#include<iostream>
using namespace std;

class point
{
public:
	point():x(0),y(0){}
	point(double a, double b) :x(a), y(b) {}
	virtual ~point()
	{
		cout << "~point" << endl;
	}

	double x;
	double y;

};

class rectangle :public point
{
public:
	rectangle():point(0,0),x1(0),y1(0){}
	rectangle(double a, double b, double c, double d) :point(a, b), x1(c), y1(d) {}
	~rectangle()
	{
		cout << "~rectangle" << endl;
	}
private:
	double x1;
	double y1;
};

int main()
{
	point* p = nullptr;
	p = new rectangle;
	delete p;
	return 0;
}

就会先调用rectangle 的析构函数,在调用point的析构函数。如果在基类的析构函数中不加virtual,那么运行结果只会调用point的析构函数

如果将基类的虚构函数写为虚函数,那么后面所有继承该基类的派生类的所有析构函数自动成为虚函数,即使名字不相同。

当基类的析构函数为虚函数时,无论指针指向的是同一类族那个类的对象,程序都会动态关联,调用相应的析构函数,对该对象所涉及的额外内存空间进行清理工作。

最好把基类的析构函数声明为虚函数,这使得后面派生类所有的析构函数均为虚函数,这样如果调用delete运算符准备删除一个对象,而delete运算符的操作对象用了派生类对象的基类指针,系统就会先调用派生类的析构函数,在调用基类的析构函数,这样整个派生类的对象被完全释放。

虚函数与重载函数比较

函数重载处理的是同一层次的函数重名问题,

而虚函数处理的是同一类族中不同派生层次 上的函数重名问题

函数重载时,参数个数和参数类别可以不一样

虚函数必须保证同名,同参数,同返回值

函数重载可以是成员函数也可以普通函数

虚函数只能是成员函数

函数重载的调用是以所传递参数序列的差别作为调用不同函数的依据

虚函数是根据对象的不同去调用不同类的虚函数

函数重载在编译时表现出多态性

虚函数在运行时表现多态性

纯虚函数

有时,基类往往表示一种抽象的概念,并不与其他事物相连,例如,封闭图形只是一个概念,但他可以派生出,三角形、四边形、五边形...

纯虚函数与一般虚函数定义格式基本相同,只是在后面多了”=0“部分表示没有函数体部分,纯虚函数的函数体由派生类给出

纯虚函数的定义形式如下:

class 类名

{

        ...

        virtual 函数类型 函数名(参数表)=0;

        ...

}

下面演示一下:基类是封闭图形,派生类有三角形,四边形。

代码如下所示:

#include<iostream>
using namespace std;
class shape
{
public:
	virtual void show() = 0;
};

class triangle :public shape
{
public:

	triangle(double a,double b,double c):a(a),b(b),c(c){}
	void show()
	{
		cout << "triangle" << endl;
	}
private:
	double a;
	double b;
	double c;

};

class quadrangle :public shape
{
public:
	quadrangle(double a,double b,double c,double d):a(a),b(b),c(c),d(d){}
	void show()
	{
		cout << "quardrangle" << endl;
	}
private:
	double a;
	double b;
	double c;
	double d;
};

int main()
{
	shape *s=nullptr;
	triangle t(1, 2, 3);
	quadrangle q(1, 2, 3, 4);
	s = &t;
	s->show();

	s = &q;
	s->show();
	return 0;
}

抽象类

如果一个类至少有一个纯虚函数,那么就称该类为抽象类,因此上面那个shape类就是抽象类。

对于抽象类的使用规则:

1.因为抽象类 中至少包含一个没有定义功能的纯虚函数,抽象类只能作为其他类的基类的来使用,不能建立抽象类对象,只能为派生类提供一个接口规范,其功能由派生类给出。

2.不允许从具体类中派生出抽象类

3.抽象类不能用作参数类型,函数返回值类型或者显示转换类型

4.可以声明抽象类类型的指针和引用,此指针可以指向它的派生类对象进而实现动态多态性

5.如果这个派生类没有重写虚函数,那么这个 派生类就是简单继承这个纯虚函数,那么这个派生类就是一个抽象类

6.在抽象类中可以定义普通成员函数或者虚函数

注意函数体为空的虚函数不是纯虚函数,函数体为空不代表没有函数体,纯虚函数没有函数体

override

如果一个成员函数是虚函数,那么在后续派生类里的同名函数都是虚函数,无须再用virtual修饰。这样就会出现以下问题:

1.这样在函数很多的情况下,就难以分辨哪些函数是派生类特有的成员函数,哪些函数继承自基类;

2.还有可能派生类可能无意使用了一个同名但函数原型不同的函数”覆盖“了基类的虚函数

#include<iostream>
using namespace std;
class base
{
public:
	virtual void f() = 0;//纯虚函数
	virtual void g()const//虚函数
	{
		cout << "base:g()" << endl;
	}
	 void h()//一般成员函数
	{
		cout << "base:h()" << endl;
	}
};

class derived :public base
{
public:
	 void f()//纯虚函数重写
	{
		cout << "derived:f()" << endl;
	}
	 void g()//不是虚函数重新,遗漏了const修饰
	{
		cout << "derived:g()" << endl;
	}
	 void h()//一般成员函数
	{
		cout << "derived:h()" << endl;
	}
};


int main()
{
	base* b = nullptr;
	derived c;
	b = &c;
	b->f();
	b->g();
	b->h();
	return 0;
}

C++11增加了一个特殊的标识符override,它可以显示地标记虚函数重写 ,明确代码编写者的意图:派生类成员函数名后面有override修饰,那么这个函数就一定是虚函数,而且函数原型也必须与基类声明一致,否则编译错误。

void f()override//纯虚函数重写
{
	cout << "derived:f()" << endl;
}

final

final可以在类名后面使用,显式的禁止类被继承,不能再有派生类

final可以在虚函数后面使用,显式的禁止该函数在派生类中再次被重写

例如

#include<iostream>
using namespace std;

class base
{
public:
	virtual void f() = 0;//纯虚函数
	virtual void g()//虚函数
	{
		cout << "base:g()" << endl;
	}
};

class derived :public base
{
public:
	void f()override final//纯虚函数重写,并不允许被重写
	{
		cout << "derived:f()" << endl;
	}
	void g()override//虚函数重写
	{
		cout << "derived:g()" << endl;
	}

};

class last final :public derived//表示last不允许被继承,last也不会再有派生类
{
	/*void f()override //纯虚函数重写,并不允许被重写
	{cout << "last:f()" << endl;}*/
	void g()//虚函数重写
	{
		cout << "last:g()" << endl;//可以重写
	}
};

 

last类在类名后使用了final,使它变成了类体系的终点

在derived类的函数f后使用了final,表示在后面的派生类中禁止重写该虚函数。

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

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

相关文章

Selenium 自动化 —— 四种等待(wait)机制

更多关于Selenium的知识请访问CSND论坛“兰亭序咖啡”的专栏&#xff1a;专栏《Selenium 从入门到精通》 ​ 目录 目录 需要等待的场景 自己实现等待逻辑 Selenium 提供的三种等待机制 隐式等待&#xff08;Implicit Waits&#xff09; 隐式等待的优点 隐式等待的缺点 …

【保姆级介绍自动化的讲解】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

mysql根据字段值关联查不同表

mysql根据字段值关联查不同表&#xff1a; 实现&#xff1a; 使用left join 结合case when 判断直接取值&#xff1a; select mp.member_id ,mp.store_id, case mp.store_type when 1 then bs.store_namewhen 2 then sc.store_namewhen 3 then be.store_name end as store_na…

Windows / Linux 查看计算机支持的最大内存

该操作一般用不到&#xff0c;主要用于给计算机扩展内存用。 一、Windows 系统 以管理员身份运行 cmd 1、查看主板最大支持内存容量 wmic memphysical get maxcapacity /format:value将返回值值是以KB为单位的&#xff0c;除以 1024&#xff0c;再除以 1024&#xff0c;即…

银行核心背后的落地工程体系丨混沌测试的场景设计与实战演练

本文作者&#xff1a; 张显华、窦智浩、卢进文 与集中式架构相比&#xff0c;分布式架构的系统复杂性呈指数级增长&#xff0c;混沌工程在信创转型、分布式架构转型、小机下移等过程中有效保障了生产的稳定性。本文分享了 TiDB 分布式数据库在银行核心业务系统落地中进行混沌测…

【AI学习】对指令微调(instruction tuning)的理解

前面对微调&#xff08;Fine-tuning&#xff09;的学习中&#xff0c;提到指令微调。当时&#xff0c;不清楚何为指令微调&#xff0c;也一直没来得及仔细学习。 什么是指令微调&#xff1f;LLM经过预训练后&#xff0c;通过指令微调提升模型的指令遵循能力。所谓指令&#xf…

【微记录】dmidecode是干什么的?常用来做什么?如何查看系统支持的PCIe版本号(本质:标准,Desktop Management Interface)

是什么 dmidecode 是一个在 Linux 系统提取硬件信息的命令行工具。DMI 代表桌面管理接口&#xff08;Desktop Management Interface&#xff09;&#xff0c;是一种标准&#xff0c;收集桌面计算机的硬件信息&#xff0c;包括系统制造商、序列号、BIOS 信息、系统资产标签等。…

AI图像生成-基本步骤

模型板块 1、新建采样器&#xff1a;新建节点-》采样器-》K采样器 2、拖动模型节点后放开&#xff0c;选择checkpoint加载器&#xff08;简易&#xff09;&#xff0c;模型新建成功 提示词板块 1、拖动正面条件节点后放开&#xff0c;选择CLIP文本编码器&#xff0c;模型新建…

UV胶的应用场景有哪些?

UV胶是一种特殊的胶水&#xff0c;其固化过程需要紫外光照射。它具有快速固化、高强度、无溶剂挥发等优点&#xff0c;因此在许多应用场景中被广泛使用。UV胶的应用场景非常广泛&#xff0c;包括但不限于以下几个方面&#xff1a; 1.电子产品组装: UV胶在电子产品的组装中扮演…

SHELL-双重循环习题练习

1.99乘法表 #!/bin/bash #99乘法表for ((second1; second<9; second)) dofor ((first1; first<second; first))do echo -n -e "${first}*${second}$[first*second]\t" done echo done ######### 首先定义了一个外循环变量second&#xff0c;初始值为1&am…

【JavaEE】Spring Web MVC入门:掌握Spring的MVC框架基础

目录 Spring Web MVC什么是Spring Web MVCMVC 定义什么是Spring MVC 学习Spring MVC1. 项目准备2. 建立连接 Spring Web MVC 什么是Spring Web MVC 官⽅对于 Spring MVC 的描述是这样的&#xff1a; Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀…

【go项目01_学习记录12】

代码组织 1 代码结构2 重构与测试2.1 安装测试功能2.2 testify 的常用断言函数 3 表组测试 1 代码结构 所有的代码写在一个main.go文件里面&#xff0c;GO编译器也是可以正常执行的。但是当代码量很庞大时&#xff0c;很难进行维护。 Go Web 程序的代码组织 单文件——反模式…

C51 单片机编程模板及编码规范

文章目录 一、C51 单片机模板创建1. 新建工程及选型2. 创建主程序文件3. 创建主程序的头文件4. 编译配置5. 其他 二、C51 的编码规范 在查阅了很多关于 C51 单片机的程序后&#xff0c;个人感觉目前网上有关 C51 单片机程序的质量参差不齐&#xff0c;很多程序的代码风格及其糟…

Kubernetes——CNI网络组件

目录 一、Kubernetes三种接口 二、Kubernetes三种网络 三、VLAN与VXLAN 1.VLAN 2.VXLAN 3.区别 3.1作用不同 3.2vxlan支持更多的二层网络 3.3已有的网络路径利用效率更高 3.4防止物理交换机Mac表耗尽 3.5相对VLAN技术&#xff0c;VXLAN技术具有以下优势 四、CNI网…

设计模式-动态代理

目录 定义 代理模式的优缺点 优点 缺点 应用场景 静态代理 动态代理 相关资料 定义 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它的概念很简单&#xff0c;它通过创建一个代理对象来控制对原始对象的访问。代理模式主要涉及两个…

分布式搜索-elaticsearch基础 概念

什么是elaticsearch: 倒排索引&#xff1a;就是将要查询的内容分成一个个词条&#xff0c;在将词条文档id存入&#xff0c;词条是唯一的。 文档词条总结: mysql和Elasticsearch概念对比: 架构: 基本概念总结:

uniapp 实现下拉刷新 下滑更新

效果图 在app或者小程序中向下滑动 会出现刷新数据 ,而上拉到底 需要更新数据 功能实现 主要俩种方式 依赖生命周期 在page.json中开启 page.json "style" : {"navigationBarTitleText" : "小小练习","backgroundTextStyle": &qu…

Transformer模型详解05-Decoder 结构

文章目录 简介结构原理第一个 Multi-Head Attention第二个 Multi-Head AttentionSoftmax 预测输出单词 简介 Transformer 模型由编码器&#xff08;Encoder&#xff09;和解码器&#xff08;Decoder&#xff09;两部分组成。这里我会着重描述解码器的结构以及在预训练、输入输…

StNet: Local and Global Spatial-Temporal Modeling for Action Recognition 论文阅读

StNet: Local and Global Spatial-Temporal Modeling for Action Recognition 论文阅读 Abstract1 Introduction2 Related Work3 Proposed Approach4 Experiments5 Conclusion 文章信息&#xff1a; 原文链接&#xff1a;https://ojs.aaai.org/index.php/AAAI/article/view/4…

期权(1):基本概念,权利金,定金,买方,卖方,零和游戏,对赌协议

期权是合约&#xff0c;权利金就是定金&#xff01; 合约到期时 买方可以选择行权&#xff0c;也可以选择不行权。代价就是定金损失。因此亏损封顶&#xff0c;但盈利无限。卖方赚的就是买方的定金&#xff0c;盈利封顶&#xff0c;但亏损无限。 从这里&#xff0c;我们看出…