C++多态的基本语法与原理剖析

多态分为两类
1.静态多态:函数重载和运算符重载属于静态多态,复用函数名
2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态区别:
1.静态多态的函数地址早绑定,编译阶段确定函数地址
2.多态多态的函数地址晚绑定,运行阶段确定函数地址

首先让我们看这段代码:

#include <iostream>
using namespace std;class Animal {public:void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {Cat cat;dospeak(cat);}int main() {test01();system("pause");return 0;
}

结果为:动物在说话

我们想要的是猫在说话,可最后输出的结果却是动物在说话,为什么呢?

因为dospeak函数地址早绑定了,在编译阶段就确定了函数地址

那么我们要怎样做才能让猫说话呢?
非常简单,就是利用动态多态,就是要让dospeak函数的地址晚绑定(在运行阶段进行绑定),我们只要在父类的同名speak函数前面加virtual关键字,现在speak函数就变成了虚函数,就解决了上述问题。

代码如下:

#include <iostream>
using namespace std;class Animal {public:virtual void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {Cat cat;dospeak(cat);}int main() {test01();system("pause");return 0;
}

结果为:猫在说话


重写的概念:
1.函数的返回类型相同
2.函数名相同
3.参数列表相同

动态多态的满足条件:
1.有继承关系
2.子类要重写父类的虚函数

动态多态的使用:
父类的指针或引用指向子类的对象

现在我们来看看多态的原理,首先我们看一下下面这段代码:

#include <iostream>
using namespace std;class Animal {public:void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {cout << "size of Animal = " << sizeof(Animal) << endl;}int main() {test01();system("pause");return 0;
}

结果为size of Animal = 1

现在我们在Animal的speak函数前面加上virtual,写成多态的形式,结果又是多少呢?

#include <iostream>
using namespace std;class Animal {public:virtual void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {cout << "size of Animal = " << sizeof(Animal) << endl;}int main() {test01();system("pause");return 0;
}

结果为:size of Animal = 4
这说明,加了virtual后,这个类的内部结构发生了改变。
那到底多了什么东西,导致这个类变成了4个字节呢?

结果:
多了指针。
现在让我们看看这其中发生的变化,
首先我们要知道:
vfptr - 虚函数(表)指针
v - virtual
f - function
ptr - pointer


vftable - 虚函数表
v - virtual
f - function
table - table


现在让我们看看Animal类内部结构:
在这里插入图片描述
Cat内部结构:
在这里插入图片描述

当子类重写父类的虚函数时,子类中的虚函数表内部会替换成子类的虚函数地址
也就是说,当我们往父类Animal的speak函数前面加上virtual时,Cat的内部结构就会变成这样:

在这里插入图片描述
当父类中的指针或者引用指向子类对象的时候,就发生了多态。

我们就相当于写了这样一段代码:
Animal &animal = cat;
animal,speak();
当我们调用animal的speak函数时,由于指向的是Cat对象,所以编译器会从Cat的虚函数表中找speak函数,就相当于在运行阶段发生了多态。

原理:
由于我们写了一个虚函数,类的内部发生了结构的改变,多了一个虚函数表指针,指向虚函数表,虚函数表内部写的是虚函数的函数入口地址,当子类重写了虚函数表,会把自身的虚函数表给替换掉,这里的替换就是Cat类中发生的替换。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始开发 VS Code 插件之 Translator Helper

本文目录Translator Helper 介绍开发概述创建第一个VS Code Extension需求分析操作文本调用Google Translation API实现核心功能配置命令插件配置测试插件打包插件发布插件CI/CDIcon及README小结Translator Helper 介绍 微软 Docs 网站上线之后&#xff0c;我发现很多中文内容是…

【实战 Ids4】║ 又一个项目迁移完成(MVC)

迎周一&#xff0c;腊月十九&#xff0c;小年倒计时新年还有两周时间就要到了&#xff0c;学习可不能停&#xff0c;这几天一直在加班调休&#xff0c;周末也如此&#xff0c;不过也是趁着半夜凌晨的时间&#xff0c;继续迁移我的项目到IdentityServer4统一认证授权中心Blog.Id…

C++string容器-赋值操作

功能描述&#xff1a; 给string字符串进行赋值 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>void test01() {string str1;str1 "hello world";cout << "str1 " << str1 << endl;…

为什么说云原生会成为未来企业技术变迁的趋势

云原生是当下的热点话题&#xff0c;但是很多人对云原生有很多误解&#xff0c;特别是传统产业物联网或工控、物联网行业对云原生显得"后知后觉"。与其在这里说是预测&#xff0c;不如说是现在进行时&#xff0c;只是由于传统产业本身的技术包袱和组织个人认识程度差…

C++vector容器-构造函数

vector数据结构和数组非常相似&#xff0c;也称为单端数组&#xff0c;在数组的尾段可以做插入&#xff0c;删除操作 vector不同于普通数组&#xff0c;vector可以动态扩展 动态扩展&#xff1a;并不是在原空间之后续接新空间&#xff0c;而是找更大的内存空间&#xff0c;然…

BeetleX网关之请求聚合

在网关服务中请求聚合是允许把多个请求打包成一个响应给请求方&#xff0c;这样不仅可以节省请求方的请求数量&#xff0c;还可以根据需求的情况整合不同业务数据响应请求。BeetleX.Bumblebee虽然并没有内置这一功能&#xff0c;但可以通过扩展的形式来支持请求聚合&#xff0c…

C++vector容器-赋值操作

vector赋值操作 功能描述&#xff1a; 给vector容器进行赋值 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector赋值操作void printVector(vector<int> &v) {for (vector<int >…

EntityFramework Core表名原理解析,让我来,揭开你神秘的面纱

上一节我们针对最开始抛出的异常只是进行了浅尝辄止的解析&#xff0c;是不是有点意犹未尽的感觉&#xff0c;是的&#xff0c;我也有这种感觉&#xff0c;看到这里相信您和我会有一些疑惑&#xff0c;要是我们接下来通过注解、Fluent APi、DbSet分别对表名进行如下设置&#x…

C++vector容器-容量和大小

vector容量和大小 功能描述&#xff1a; 对vector容器的容量和大小操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector容器的容量和大小操作void printVector(vector<int > &v) {…

openresty+mysql+乱码_openresty记录响应body乱码问题

问题背景最近新上了一个功能&#xff0c;openresty通过syslog记录请求日志&#xff0c;然后由logstash推送至ES。测试上线时未发现这个问题&#xff0c;在日常查看日志的过程中&#xff0c;发现logstash推送有错误日志&#xff0c;错误内容为&#xff1a;Error parsing json&am…

【Azure学习.01】先从账号注册开始

本文部分内容配套视频&#xff1a;https://www.bilibili.com/video/av82898957马上要放假了&#xff0c;决定在家里简单了解一下Azure云服务&#xff0c;虽然公司其他部分用到了这个Azure&#xff0c;但是我还是没有接触到&#xff0c;只是听说很贵&#xff0c;好几千每天&…

C++vector容器-插入和删除

vector插入和删除 功能描述&#xff1a; 对vector容器进行插入&#xff0c;删除操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector插入和删除void printVector(vector<int > &v…

C++vector容器-数据存取

vector数据存取 功能描述&#xff1a; 对vector中的数据的存取操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector>//vector容器 数据存取 void test01() {vector<int >v1;for (int i 0; i &l…

如何快速融入团队(四)

作者&#xff1a;邹溪源&#xff0c;长沙资深互联网从业者&#xff0c;架构师社区特邀嘉宾&#xff01;01不知不觉这个系列已经开始第四篇的&#xff0c;其实我的原始意图只是思考一下如果有幸加入一个新团队&#xff0c;我们在思想和行动上该做哪些准备呢。不过随着内容的逐渐…

C++vector容器-互换容器

vector容器互换 功能描述&#xff1a; 实现两个容器内元素进行互换 函数原型&#xff1a; swap(vec);//将vec与本身的元素互换 1.基本使用 代码如下: #include <iostream> using namespace std; //vector容器互换 #include <vector> //1.基本使用void printVect…

.NET 状态机Automatonymous快速入门

介绍 Automatonymous是.NET开发人员的状态机库。它提供了一种流畅的语法来声明状态机&#xff0c;包括状态&#xff0c;事件&#xff08;支持触发器和数据事件&#xff09;以及状态/事件活动。尽管Automatonymous在简单的状态机上非常容易使用&#xff0c;但它具有许多高级功能…

BeetleX实现HTTP协议详解

在传统网络服务中扩展中需要处理Bytes来进行协议的读写&#xff0c;这种原始的处理方式让工作变得相当繁琐复杂&#xff0c;出错和调试的工作量都非常大&#xff1b;组件为了解决这一问题引用Stream读写方式&#xff0c;这种方式可以极大的简化网络协议读写的工作量&#xff0c…

euclidea4攻略_Euclidea几何构建11.4通关攻略

Euclidea几何构建10.2通关攻略Euclidea游戏10.2怎么过&#xff1f;下面小编为大家带来Euclidea几何构建10.2通关攻略&#xff1a;更多攻略不断更新中——Euclidea游戏全关卡通关攻略大全分两次做图第一次&#xff0c;画圆就成了&#xff0c;具体看图应该能懂。第二次&#xff0…

C++set容器-构造和赋值

set基本概念 简介&#xff1a; 所有元素都会自动在插入时自动被排序&#xff0c;set容器也叫集合容器 本质&#xff1a; set/multiset属于关联式容器&#xff0c;底层结构是用二叉树排序 set和multiset区别&#xff1a; 1.set不允许容器中有重复的元素 2.multiset允许容器中有…

(1)解锁MongoDB replica set核心姿势

本文倒腾目前大热的MongoDB Replica Set集群&#xff0c;在倒腾的同时串讲一些 MongoDB特性。 副本集Replica Set是一个术语&#xff0c;定义具有多节点的数据库集群&#xff0c;这些节点具有主从复制(master-slave replication) 且节点之间实现了自动故障转移。 这样的结构通常…