C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数

目录

什么是多态性?

概念

分类

向上类型转换

功能的早绑定和晚绑定

绑定

绑定与多态的联系

编译时多态(功能的早绑定)

运行时多态(功能的晚绑定)

一般而言

实现功能晚绑定——虚函数

虚函数定义的说明


什么是多态性?

概念

书上的表示是——向不同的对象发送同一个消息,不同的对象在接受时会有不同的反应,产生不同的动作。

我们在上课时,老师是这么解释的:在一个学校里,每个人都有不同的工作,当校长发出号令“开工”,每个人就开始工作(属于自己的那份工作)。

具体一点:多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,从而可以使用相同的口令来调用相应函数——一个接口,多个方法。

分类

多态性可以分为——参数多态,包含多态,重载多态,强制多态。

参数多态:函数模板,类模板

由函数模板实例化的各个函数具有相同的操作,而这些函数的参数类型却各不相同

由类模板实例化的各个类具有相同的操作,而操作对象的类型各不相同

包含多态定义于不同类之间的同名成员函数,主要通过虚函数来实现。

重载多态:函数重载,运算符重载

函数重载有就是在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数、类型、类型顺序)不同。

运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型时导致不同的行为。 

强制多态:是指将一个变元的类型加以变化,以符合一个函数(或者操作)的要求

如加法运算符在进行浮点数于整形数相加时,首先进行类型强制转换。把整型数变为浮点数再相加的情况。

向上类型转换

向上类型转换就是把一个派生类对象当成基类对象来用 

注意:

向上类型转换是安全的

向上类型转换可以自动完成

向上类型转换的过程会丢失子类信息

#include<iostream>
using namespace std;

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


	double x;
	double y;

};

class rectangle:public point
{
public:
	rectangle(double a,double b,double c,double d):point(a,b),x1(c),y1(d){}
	void area(void)
	{
		cout << "rectangle:" << (x-x1)*(y-y1)<< endl;
	}

private:
	double x1;
	double y1;
};

class circle :public point
{
public:
	circle(double a,double b,double c):point(a,b),r(c){}
	void area(void)
	{
		cout << "circle:" <<r*r*3.14<< endl;
	}
private:
	double r;
};


void calcarea(point& p)
{
	p.area();
}


int main(void)
{
	point p(0, 0);
	rectangle r(0, 0, 1, 1);
	circle c(0, 0, 1);
	cout << "直接调用:" << endl;

	p.area();
	r.area();
	c.area();
	cout << "通过calearea函数调用:" << endl;
	calcarea(p);
	calcarea(r);
	calcarea(c);

	return 0;
}

再caleare函数中,接受point的对象,但也不拒绝point的派生类对象,无需类型转换就可以将rectangle和circle的对象传给calearea。这也就是向上类型转换,可以将派生类转换为基类,这也导致rectangle和circle类的接口变窄。

可以看到通过calearea函数调用时,输出的全是“point:0",显然不是我们希望可看到的,我们希望通过基类的引用直接调用到相应的派生类成员函数。 

也就是当calearea函数中的对象是rectangle时调用rectangle中的area函数;

当calearea函数中的对象时circle的对象时调用cricle中的area函数。

为了解决这个问题需要了解功能的早绑定和晚绑定

功能的早绑定和晚绑定

绑定

确定操作具体对象的过程称为绑定。

绑定是指计算机程序自身彼此关联的过程,把一个标识符和一个存储地址联系在一起(把一条消息和一个对象的方法相结合的过程)。

绑定与多态的联系

按照绑定进行的阶段不同分为:功能的早绑定和功能的晚绑定

多态从实现的角度可以分为:编译时多态和运行时多态

两种绑定方法分别对应多态的两种实现方式

编译时多态(功能的早绑定)

编译过程中确定了同名操作的具体操作对象,在程序执行前期,系统就可以确定同名标识要调用那一段程序代码。

有些多态类型(重载多态,强制多态,参数多态)可以通过早绑定确定同名操作的具体操作对象

运行时多态(功能的晚绑定)

程序运行过程中动态的确定操作所针对的具体对象,在编译过程中无法解决绑定问题,等程序开始运行之后再来确定,包含多态就是通过晚绑定来确定具体操作对象的。

一般而言

编译型语言(C,PASCAL)都采用功能的早绑定,

解释型语言(LISP,Prolog)都采用晚绑定

早绑定具有函数调用速度快,效率高,但缺乏灵活性,晚绑定恰恰相反。

C++由C语言发展而来,为了保持C语言的高效性,C++仍采用编译型也就是早绑定,为了解决某些特定情况,发明了虚函数,让C++可部分采用功能的晚绑定。
C++中,编译时的多态性主要通过函数重载和运算符重载实现。运行时的多态主要通过虚函数来实现。

实现功能晚绑定——虚函数

虚函数提供了一种更为灵活的多态性机制。虚函数允许函数调用与函数体之间的联系在运行时才建立,也就是在运行时才决定同名操作的具体操作对象

虚函数的定义和作用

虚函数定义在基类定义,在成员函数声明前加上virtual,定义语法如下:

virtual 函数类型 函数名(形参表)

{
        函数体;

}

在基类中定义虚函数,

在派生类中重写虚函数,重写时必须满足同名,同参数,同返回值。

使用时必须通过指针或者引用来调用

上面的例子基类时point,修改:我们只需要将point类中的area函数前面加上virtual就可以达到想要的效果。

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


	double x;
	double y;

};

上面的代码是通过引用调用的,下面我们用指针来调用 ,也就是形参为指针,实参传地址。具体代码如下:

void calcarea(point* p)
{
	p->area();
}


int main(void)
{
	point p(0, 0);
	rectangle r(0, 0, 1, 1);
	circle c(0, 0, 1);
	cout << "直接调用:" << endl;

	p.area();
	r.area();
	c.area();
	cout << "通过calearea函数调用:" << endl;
	calcarea(&p);
	calcarea(&r);
	calcarea(&c);

	return 0;
}

虚函数定义的说明

1.派生类应该从它的基类公有派生

2.必须先在基类中定义虚函数(并不一定是最高层的基类)

3.在派生类中重写虚函数是virtual可以写也可以不写

4.一个虚函数无论被继承多少次,都保持其虚函数特性

5.虚函数必须在其类的成员函数中,不能是友元函数,不能是静态成员函数

6.内联函数不能是虚函数

7.构造函数不能是虚函数

8.析构函数可以是虚函数

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

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

相关文章

Docker 使用 Fedora 镜像

Fedora 在 Docker 中的使用也非常简单&#xff0c;直接使用命令 docker run -it fedora:latest bash 就可以 pull 到本地的容器中并且运行。 C:\Users\yhu>docker run -it fedora:latest bash Unable to find image fedora:latest locally latest: Pulling from library/fed…

项目实施方案:多点异地机动车典型系统试验状态可视监控系统

目录 一、需求分析 1.1项目背景 1.2项目概述 二、系统优势 2.1兼容性能力强 2.2接入协议多样 2.3并发能力强 2.3.1 单平台参数 2.3.2 多平台性能参数 2.4 系统稳定性 三、建设目标 3.1安全性 3.2可扩展性 3.3易用性 3.4兼容性 3.5 响应能力 四、系统整体解决方…

Linux修炼之路之yum和vim编辑器

目录 一&#xff1a;Linux软件包管理器yum 二&#xff1a;vim编辑器 vim的三种模式及互相转换 命令模式 底行模式 三&#xff1a;普通用户的sudo指令(修改信任名单) 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 一&#xff1a…

创建一个Spring Boot项目

文章目录 一、如何创建一个Spring Boot项目1.1 项目创建&#xff1a;专业版 or 社区版 or 网站创建1.2 数据配置1.3 项目启动1.4 代码编写 二、Spring Boot 项目文件介绍三、Web服务器四、根据HTTP状态码解决bug4.1 4044.2 500 五、Spring VS Spring Boot VS Spring Web MVC5.1…

AI“源神”启动!Llama 3发布,开闭源之争战局生变

在AI的世界里&#xff0c;开源与闭源的较量一直是科技界的热门话题。 今年年初&#xff0c;埃隆马斯克在对OpenAI及其CEO萨姆奥特曼提起诉讼时&#xff0c;就对OpenAI逐渐不公开其模型研究相关细节的行为大加谴责。“时至今日&#xff0c;OpenAI公司网站还宣称&#xff0c;它的…

JVM从1%到99%【精选】-运行时数据区

目录 1.总览运行时数据区 2.内存溢出 3. 程序计数器 4.虚拟机栈 5.本地方法栈 6.堆 7.方法区 8.直接内存 1.总览运行时数据区 Java虚拟机在运行Java程序过程中管理的内存区域,称之为运行时数据区。运行时数据区可以分为方法区、堆、虚拟机栈、本地方法栈、程序计数器…

美国分析人工智能技术对网络格局的影响(下)

文章目录 前言六、边际效应和威胁七、将人工智能纳入美国网络战略总结前言 以生成式人工智能在网络犯罪市场中的作用为例。利用生成式人工智能(无论是通过生成文本、语音还是图像)的近期威胁之一是在网络操作的初始访问阶段将此类内容用于社会工程和鱼叉式网络钓鱼。例如,一…

vscode 通过ssh 远程执行ipynb +可以切换conda env

主要是保证几个点 远程服务器python 环境没问题 conda这些也都有的ssh的账户 是有conda权限的没有免密就输入密码 免密教程就是最基本的那种 公钥copy过去就行了vscode 那几个插件都要装好 开始操作 首先 vscode 点击左侧工具栏中的扩展&#xff0c;搜索“ssh”&#xff0c;…

7.STL中string的一些超常用函数 (附习题)

目录 1.find 2.atoi 3.to_string 4.getline 【leetcode 习题】 387.字符串中的第一个唯一字符 125. 验证回文串 1.find 1.查找第一次出现的目标字符串&#xff1a;说明&#xff1a;如果查找成功则输出查找到的第一个位置&#xff0c;否则返回-1&#xff1b; s1.find(s2…

linux安装Openresty

安装必要的依赖库 指定仓库地址 下载openresty 添加环境变量 vi /etc/profile i export NGINX_HOME/usr/local/openresty/nginx/ export PATH${NGINX_HOME}/sbin:$PATH esc :wq source /etc/profile #启动 nginx # 重启 nginx -s reload #关闭 nginx -s stop

2024年低碳发展与新能源技术国际学术会议(ICLCDNET 2024)

2024年低碳发展与新能源技术国际学术会议&#xff08;ICLCDNET 2024) 2024 International Conference on Low Carbon Development and New Energy Technologies 一、【会议简介】 随着全球气候变化的日益严峻&#xff0c;低碳发展和新能源技术已成为国际社会共同关注的焦点。在…

python怎么读取xml

引入XML组件&#xff1a;import xml.dom.minidom。 创建一个xml文件&#xff0c;<?xml version"1.0" encoding"utf-8"?>。 加载读取XML文件&#xff0c;xml.dom.minidom.parse(abc.xml)&#xff0c;这是xml文件的对象。 获取XML文档对象&#xff0…

柯桥法语学习-5大法语听写网站:全力助攻你的dictée!

提到法语dicte&#xff0c;绝对可是法语学生们的老大难&#xff0c;简直就是心痛得不能自已啊&#xff01;所以今天&#xff0c;法语君整理了5个听写网站助攻大家的dicte哦&#xff01; Projet Voltaire 01 一个很容易让你对dicte上瘾的APP 写邮件、实习报告或者动机信时&…

数据新探:用Python挖掘互联网的隐藏宝藏

Hello&#xff0c;我是你们的阿佑&#xff0c;今天给大家上的菜是——数据存储&#xff01;听起来枯燥无味&#xff1f;错了&#xff01;阿佑将带你重新认识数据存储的艺术。就像为珍贵的艺术品寻找完美的展览馆&#xff0c;为你的数据选择合适的存储方式同样重要&#xff01; …

基准电流源电路仿真

1.补全电路 2.更改vpluse属性 3.添加tran仿真&#xff0c;因为加入启动电路主要看的就是tran仿真 4.启动仿真 5.看电路曲线 先点这个main form 不用选择ok&#xff0c;直接点中四条线&#xff0c;中间第2条曲线如果出现那样一个小波动后面没有起伏就说明成功了。

一篇文章带你入门CSRF

1.什么是CSRF 用一个形象生动的比喻就是&#xff1a; 你给朋友的房子留下了备用钥匙&#xff0c;但是有人偷偷拿走了这把钥匙&#xff0c;然后用这把钥匙进入了你朋友的房子并做了各种坏事。你朋友以为只有你能使用这把钥匙&#xff0c;所以没对任何操作产生怀疑。 在这个比…

.NET周刊【5月第2期 2024-05-12】

国内文章 C#在工业数字孪生中的开发路线实践 https://mp.weixin.qq.com/s/b_Pjt2oii0Xa_sZp_9wYWg 这篇文章探讨了C#在工业数字孪生技术中的应用&#xff0c;介绍了三种基于C#的数字孪生系统实现方案&#xff1a; WPF Unity&#xff1a;结合WPF技术和Unity引擎&#xff0c…

算法练习day8

反转字符串 代码随想录 0344.反转字符串 344. 反转字符串 - 力扣&#xff08;LeetCode&#xff09; &#xff08;用时&#xff1a;0.05小时&#xff09; 思路 这道题很简单也很经典。 字符串的反转方法有很多&#xff0c;我这里是用for循环通过数组长度和下标计算来交换。…

如何用Rust获取CPU、内存、硬盘的信息?

目录 一、用Rust获取CPU、内存、硬盘的信息 二、知识点 systemstat 一、用Rust获取CPU、内存、硬盘的信息 首先&#xff0c;需要添加systemstat库到Cargo.toml文件&#xff1a; [dependencies] systemstat "0.2.3" 在Rust代码中使用它&#xff1a; extern crat…

pip镜像源

1.1 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple 1.2 阿里云 https://mirrors.aliyun.com/pypi/simple/ 1.3 网易 https://mirrors.163.com/pypi/simple/ 1.4 豆瓣 https://pypi.douban.com/simple/ 1.5 百度云 https://mirror.baidu.com/pypi/simple/ 1.6 中科大 ht…