多态性之编译期多态和运行期多态(C++版)

C++ 运行期多态和编译器多态 C++多态有多种实现方式,在面对对象编程时,采用的是运行期多态,也称动态多态。在泛型编程中,多态基于模板的具现化与函数的重载解析,这种多态在编译期进行,也称编译器多态或者静态多态。 运行期多态 运行期多态归根结底就是类继承的一个特性。我们习惯于抽象出不同功能的对象的共有功能集合,在基类中将这些共有功能声明为虚函数(也称虚接口),然后由子类去重写这些虚函数,以实现多态。 class Animal ... 阅读详情

多态性之编译期多态和运行期多态(C++版)


    C++中最为经典的就是多态性,多态性充分体现了面向对象的思想,并且是C++与C的最大区别之一。多态性分为编译期多态和运行期多态,也称为静态多态和动态多态,有些人也称其为编译时多态和运行时多态,不管什么称呼,万变不离其宗,一个是编译期的静态的多态,一个是运行期的动态的多态,那么它们在C++中分别体现在哪里呢?又有什么区别呢?下面将详细介绍(重点是运行期多态)。

    1. 编译期多态(静态多态)


    编译期多态,正如其名,就是在编译期确定的一种多态性。这个在C++中主要体现在函数模板,这里需要注意的是函数重载和多态无关,很多地方把函数重载也误认为是编译期多态,这是错误的。

     那么函数模板是如何体现编译期多态的呢?下面举一个简单的例子就可以明白。

[cpp]  view plain  copy
  1. // 例1:函数模板体现出编译期多态  
  2. #include <iostream>  
  3.   
  4. template <typename T>  
  5. T add(T a, T b)  
  6. {  
  7.     T c = a + b;  
  8.     return c;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i1 = 1;  
  14.     int i2 = 2;  
  15.     int iResult = 0;  
  16.   
  17.     iResult = add(i1, i2);  
  18.     std::cout << "The result of integer is " << iResult << std::endl;  
  19.   
  20.     double d1 = 1.1;  
  21.     double d2 = 2.2;  
  22.     double dResult = 0;  
  23.   
  24.     dResult = add(d1, d2);  
  25.     std::cout << "The result of double  is " << dResult << std::endl;  
  26.   
  27.     return 0;  
  28. }  

    从例1中可以看到,我们定义了一个函数模板add,用来求两个数的和,这两个数的数据类型在使用时才知道。main函数中使用了两个int值的求和以及两个double值的求和,这里就体现了多态性,即在编译期,编译器根据一定的最佳匹配算法确定函数模板的参数类型到底是什么,这就体现了编译期的多种状态。

    当说到多态性的时候一般都默认指运行期多态,所以编译期多态大家只要知道是如何表现的就可以了,下面重点来讨论运行期多态。    

    2. 运行期多态(动态多态)


    运行期多态主要是指在程序运行的时候,动态绑定所调用的函数,动态地找到了调用函数的入口地址,从而确定到底调用哪个函数。在C++中,运行期多态主要通过虚函数来实现,并且一定要有继承关系,下面举一个简单的例子来讲解。

[cpp]  view plain  copy
  1. // 例2:虚函数和继承关系体现运行期多态  
  2. #include <iostream>  
  3.   
  4. class parent  
  5. {  
  6. public:  
  7.     parent() {}  
  8.   
  9.     // 父类的虚函数  
  10.     virtual void eat()  
  11.     {  
  12.         std::cout << "Parent eat." << std::endl;  
  13.     }  
  14.   
  15.     // 注意这个并不是虚函数!!!  
  16.     void drink()  
  17.     {  
  18.         std::cout << "Parent drink." << std::endl;  
  19.     }  
  20. };  
  21.   
  22. class child : public parent  
  23. {  
  24. public:  
  25.     child () {}  
  26.   
  27.     // 子类重写了父类的虚函数  
  28.     void eat()  
  29.     {  
  30.         std::cout << "Child eat." << std::endl;  
  31.     }  
  32.   
  33.     // 子类覆盖了父类的函数,注意由于父类的这个函数  
  34.     // 并不是虚函数,所以不存在继承后重写的说法  
  35.     void drink()  
  36.     {  
  37.         std::cout << "Parent drink." << std::endl;  
  38.     }  
  39.   
  40.     // 子类特有的函数  
  41.     void childLove()  
  42.     {  
  43.         std::cout << "Child love playing." << std::endl;  
  44.     }  
  45. };  
  46.   
  47. int main()  
  48. {  
  49.     parent* pa = new child();  
  50.     pa->eat();       // 运行期多态的体现!!!  
  51.     pa->drink(); // 这里调用的还是父类的drink,所以并不是多态!!!  
  52.     // pa->childLove(); // 编译出错,父类的指针不能调用父类没有的函数  
  53.   
  54.     return 0;  
  55. }  
[cpp]  view plain  copy
  1. 运行结果:  
  2.   
  3. Child eat.  
  4. Parent drink.  

    例2写得比较完善,说明了很多问题,我们先来看主要的,即多态性的体现。注意,在C++中只能用指针或引用来实现多态,不能通过普通的对象来实现多态,例2中使用的是指针的形式。我们来仔细分析一下。

    第一,在我们的父类即parent中定义了一个虚函数(virtual关键字修饰的函数)---eat(),既然是虚函数,那么我们的子类就可以重写这个函数(注意这里强调是重写,而不是重载,也不是覆盖,重要的事情说三遍,是“重写!重写!重写!”)。我们的子类child中重写了eat()函数,至于父类和子类中的其他函数暂且先忽略,后面再讲解,这里只关注多态性相关的点。然后,在main函数中,我们定义了一个父类的指针parent,但是注意,我们虽然定义的是父类的指针,但是我们指向的是子类对象,即new的是child对象,这里涉及到向上转型,即将子类对象向上转型到了父类的指针所指。总之,一句话来说就是定义一个父类指针,指向子类对象,然后我们用父类的这个指针去调用eat()函数,这里就是多态发生的地方。从运行结果可以看到,实际上调用的是子类的eat()函数,并不是父类的eat()函数,这是因为虚函数,父类定义的是虚函数,而子类重写了这个函数,虽然我们定义的是父类指针,但是实际上指向的是子类对象,那么在运行期间,就会找到动态绑定到父类指针上的对象就是子类对象,然后实际上运行期间就是找到了子类对象中eat()函数的入口地址,然后调用了子类的eat()函数,这就是运行期多态。说了这么多,听起来十分绕口,貌似很难理解,但是大家仔细想想,总结成一句话就是:“定义父类指针并指向子类对象,此时用父类指针去调用一个特殊的函数,即父类中该函数是虚函数,而子类重写了这个虚函数,此时调用的这个函数就在运行期间动态地绑定到了指针实际所指的对象,即子类对象,从而去调用子类中的这个函数”。

    第二,说完了多态,我们来看看例2中其他需要注意的地方。我们发现在main函数中pa指针还调用了drink()函数,最终的运行结果显然调用的是父类的drink()函数,那么这里为什么没有多态呢?原因很简单,因为drink()函数不是虚函数,所以根本不存在多态这一特性,虽然父类和子类中都有drink()这个函数,但是子类仅仅是覆盖或者说隐藏了父类的drink()函数,并不是重写。而我们的指针是父类指针,所以必定要去调用父类的drink()函数。

    第三,我们来看看最后一点。细心的朋友会发现,在子类child中,有一个只有它有而父类没有的函数,即childLove()函数,该函数是子类特有的,和父类没有任何关系,所以在main函数中用pa指针去调用这个函数会出错,因为父类指针根本访问不到子类的这个函数。这也是多态性的一个缺陷,即父类的指针只能访问子类中重写了父类中的那些虚函数,而不能访问子类新增的特有的函数。

    最后我们来看一个纯虚函数实现多态性的例子。

[cpp]  view plain  copy
  1. // 例3:纯虚函数和继承关系体现运行期多态  
  2. #include <iostream>  
  3.   
  4. // 父类因为包含纯虚函数,所以该类是抽象类,即不能定义对象  
  5. class parent  
  6. {  
  7. public:  
  8.     parent() {}  
  9.   
  10.     // 父类的纯虚函数  
  11.     virtual void eat() = 0;  
  12. };  
  13.   
  14. class child : public parent  
  15. {  
  16. public:  
  17.     child () {}  
  18.   
  19.     // 子类重写了父类的纯虚函数  
  20.     void eat()  
  21.     {  
  22.         std::cout << "Child eat." << std::endl;  
  23.     }  
  24. };  
  25.   
  26. int main()  
  27. {  
  28.     // parent pa0;  // 编译期会出错,因为抽象类不能定义对象  
  29.   
  30.     // 注意抽象类虽然不能定义对象,但是可以定义指针用来指向具体类  
  31.     parent* pa = new child();  
  32.     pa->eat();       // 运行期多态的体现!!!  
  33.   
  34.     return 0;  
  35. }  

[cpp]  view plain  copy
  1. 运行结果:  
  2.   
  3. Child eat.  

    例3和例2基本上是一样的,省略了很多函数,这里多态性的体现和例2也是完全一样的,之所以举这个例子是为了解释下抽象类用来实现多态的一个理解误区。从例3中就可以看到,纯虚函数就是一个函数后面加上"=0",而没有任何实现,那么包含纯虚函数的类就自然成为了抽象类,而抽象类是不能定义对象的,这也就是为什么main函数中的第一行会出错。注意,继承抽象类的具体类必须实现抽象类中的纯虚函数,否则也会出错。这里想强调一个误区,很多人觉得既然抽象类不能定义对象,那么main函数中的parent *pa为什么没有出错,这是因为抽象类虽然不能定义对象,但是可以定义指针,用来指向具体类,从而实现多态,一定要分清楚C++中的指针、引用、对象三者之间的关系,不要一概而论。

    3. 总结


    多态性是面向对象中十分重要的一个特性,大家务必要掌握,虽然初学起来感觉很难理解,但是多思考下,看完例子后自己写一个多态性的例子就会清楚一些。平常我们所指的多态性一般都是说运行期多态,所以大家重点掌握运行期多态。本篇文章可能存在一些纰漏,欢迎大家指正,谢谢。
迪文DGUSII串口屏中文显示实战:手把手教你制作16x16点阵字库 本文提供了一份迪文DGUSII串口屏16x16点阵中文字库制作的完整实战指南。从显示原理、字体选择与参数设置,到使用FontLib Make工具生成字库文件,再到部署、调用及存储空间优化,手把手教你解决中文显示难题,确保界面文字既美观又稳定。 阅读详情

相关推荐

华大HC32F460从零到200MHz:手把手教你配置时钟系统(附避坑指南)

本文详细解析了华大HC32F460 MCU的时钟系统配置,从启动过程、时钟树分析到实战配置200MHz系统时钟。文章手把手指导开发者如何正确配置外部晶振、MPLL锁相环及总线分频,并提供了硬件检查、代码解读及常见问题排查的避坑指南,帮助用户从零构建稳定可靠的高性能时钟环境。

net55的博客 296

编译时多态和运行时多态

编译时多态和运行时多态 多态分为两种情况:编译时多态和运行时多态。如果在编译时能够确定执行多态方法称为编译时多态,否则称为运行时多态。 一、编译时多态 方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法。 方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。例如,以下声明p、m引用本类实例,调用toString()方法是编译时多态。 public class Test { public static void

twx31420的博客 4997

cadence capture CIS 之添加数据库

2021-08-20 cadence capture CIS 之添加数据库准备一、添加数据源 准备 1、数据库文件(*.mdb) 2、电脑上安装好 cadence 软件 一、添加数据源 打开“ ODBC数据源管理器” ( 路径:C:\Windows\SysWOW64\odbcad32.exe ) ...

weixin_42256550的博客 6054

java面向对象三大特性之多态---编译时多态和运行时多态详解

一.引言 1.什么是多态? 说到重载和重写,大家可能都知道。它们都是多态性的体现,那么说什么是多态呢?多态是指允许不同子类型的对象对同一行为作出不同的响应。例如在生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态描述的就是这样的状态。 2.多态的分类. 多态性分为编译时的多...

weixin_43951932的博客 7010

QMT Python API 实战指南:从安装到策略开发的完整流程

本文提供了一份详尽的QMT Python API实战指南,涵盖从环境配置到策略开发的完整流程。文章深入解析了xtdata行情模块与xttrader交易模块的核心架构与协作方式,并通过一个双均线策略实例,手把手教你如何获取数据、计算信号并执行交易,是量化交易开发者快速上手QMT Python接口文档的实用教程。

butter的博客 1416

ICC2:postmask ECO参考脚本

更多学习内容请关注「拾陆楼」知识星球。

m0_61544122的博客 882

【C++】09.多态

详解多态的实现,虚函数表及多态的底层原理

caryon的博客 2021

水与光的奇妙“切割之舞”:水导激光切割技术探秘

水导激光切割技术的诞生,是材料加工领域不断追求高精度、高质量加工的成果。传统激光切割技术在加工过程中,材料会因瞬间高温而产生热变形、热影响区大以及切割面粗糙等问题,这些弊端在对一些高精度、热敏性材料的加工中尤为突出 ,迫切需要一种新的技术来克服这些难题。水导激光切割技术的起源可以追溯到 20 世纪 80 年代。1986 年,德国公司 Aesculap-Werke AG 首次提出了将水流引入激光切割过程的创新想法,并制造出首代水导激光设备。不过,当时的技术尚处于雏形阶段,仅仅是在光纤出口添加了一小柱水流,激光

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 1673

多态性之编译期多态和运行期多态(JAVA版)

编译期多态和运行期多态(JAVA版)     上一篇讲述了C++中的多态性,由于多态性是面向对象编程中常用的特性,所以JAVA作为面向对象的主流语言自然也有多态性,它的多态性其实和C++的概念差不多,只是实现形式和表现形式不一样。在C++中可能还会提到多态的划分,但是在JAVA中可能很多人都不会听到编译期多态和运行期多态这种划分,一般我们说到多态都是指运行期多态,因为这才是面向对象思想的

君临天下的博客 3030

【RT-DETR有效改进】全新的SOATA轻量化下采样操作ADown(轻量又涨点,附手撕结构图)

本文给大家带来的改进机制是利用2024/02/21号最新发布的YOLOv9其中提出的ADown模块来改进我们的Conv模块,其中YOLOv9针对于这个模块并没有介绍,只是在其项目文件中用到了,我将其整理出来用于我们的YOLOv8的项目,经过实验我发现该卷积模块(作为下采样模块)首先可以大幅度降低参数值,其次其精度上也有很高的提升,同时本文的内容目前网络上并无其它人总结(也是最新发布的,可以说BUff是集满了)大家可以尝试以下在自己数据集上的效果。

Snu77的博客 4772

手把手实现STM32+ESP8266+原子云服务器+手机APP应用——第三节-编写STM32程序实现STM32+ESP8266+原子云服务器+手机APP互相通信—远程数据传输及控制灯

接上一篇,本节使用原子云服务器。编写STM32程序实现STM32+ESP8266+原子云服务器+手机APP互相通信—远程数据传输及控制灯。使用的硬件包括:STM32F103(任意其他款系列也可以的)、正点原子ATK-ESP8266、LED灯。实现编写STM32程序代码来传输单片机数据到原子云服务器和手机APP进行显示,同时通过手机APP和原子云服务器可以远程控制单片机,例如本节实现远程点/灭灯,以此可以扩展开发更多的功能。本专栏本系列的相关文章可查看下面链接:

嵌入式阿齐Archie 8414

C++编译期多态与运行期多态

来源:https://www.cnblogs.com/QG-whz/p/5132745.html前言今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合...

编程与实战的博客 1283

【AI智能体】QClaw 对接GitHub处理自动化任务实战操作详解

QClaw 对接GitHub处理自动化任务实战操作详解

congge 4869

C++ 多态性有哪些

C++多态性有哪些?       概念:指相同的对象收到不同的消息或者不同的对象收到相同的消息时产生的不同的实现动作。 C++支持两种多态:编译时多态(静态)、运行时多态(动态) (1)编译时多态:就是在编译期确定的一种多态。在C++中主要体现在函数模板,这里需要注意,函数重载和多态无关,很多地方把函数重载误认为是编译多态,这是错误的???      举例说明一下函数模板是如何体

YF_Li123的博客 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++的运行期多态和编译期多态

前言 今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合,其中泛型编程与基于它的STL是C++发展中最为出彩的那部分。在面向对象C++编程中,多态是OO三大特性之一,这种多态称为运行期多态,也称为动态多态;在泛型编程中,多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态或静态多态。在本文中,我们将了解:

Roykuang的专栏 757

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

java多态编译_多态性之编译期多态和运行期多态(JAVA版)

多态性之编译期多态和运行期多态(JAVA版)上一篇讲述了C++中的多态性,因为多态性是面向对象编程中经常使用的特性,因此JAVA做为面向对象的主流语言天然也有多态性,它的多态性其实和C++的概念差很少,只是实现形式和表现形式不同。在C++中可能还会提到多态的划分,可是在JAVA中可能不少人都不会听到编译期多态和运行期多态这种划分,通常咱们说到多态都是指运行期多态,由于这才是面向对象思想的真正体现之...

weixin_39888412的博客 354

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

c++编译期多态与运行期多态,显示接口和隐式接口

运行期多态(runtime polymorphism) 运行期多态的设计思想要归结到类继承体系的设计上去。对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些功能声明为虚接口(虚函数),然后由子类继承基类去重写这些虚接口,以实现子类特有的具体功能。典型地我们会举下面这个例子: 运行期多态的实现依赖于虚函数机制。当某个类声明了虚函数时,编译器将为该类对象安插一个虚函数...

shayne000的博客 468

c++ 多态 运行时多态和编译时多态_软件特攻队|针对C++编译期多态与运行期多态,我有话说...

时至今日的C++已经发展成为一种多次语言所组成的语言集合,而其中泛型编程与基于它的STL是C++发展历程中最为精彩的那一部分。在C++的面向对象编程中,多态是OO三大特性之一,我们称为运行期多态,也称它为动态多态;但在泛型编程中,多态是基于模板的具现化与函数的重载解析,由于这种多态发生于编译期,所以称它为编译期多态或静态多态。运行期多态运行期多态的设计来源于类继承体系的设计上。面对有相关功能的对象...

weixin_39949506的博客 290

c++ 多态 运行时多态和编译时多态_C++学习刷题18--多态性的实现

一、前言本部分为C++语言刷题系列中的第18节,主要讲解这几个知识点:多态性的概念、虚函数与覆盖函数、虚析构函数、纯虚函数与抽象类。欢迎大家提出意见、指出错误或提供更好的题目!二、知识点讲解知识点1:多态性的概念· 在C++语言中,多态性是指对相同名称函数的调用,在不同情况下能调用不同的实现函数。· 通过对重载函数的调用实现的多态性,称为静态多态性。在程序编译阶段,编译器通过实参匹配形参的方式确定...

weixin_39912566的博客 2605

【C++】C++ 多态的底层实现

C++通过虚函数和虚表实现了强大的多态性机制,允许程序在运行时动态地决定调用哪个函数。这种机制虽然引入了一定的内存和性能开销,但在面向对象编程中提供了极大的灵活性。理解其底层实现对于编写高效、健壮的C++代码具有重要意义。

2403_86785171的博客 1758

编译期多态和运行时多态

前言 今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合,其中泛型编程与基于它的STL是C++发展中最为出彩的那部分。在面向对象C++编程中,多态是OO三大特性之一,这种多态称为运行期多态,也称为动态多态;在泛型编程中,多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态或静态多态。在...

168

codeblocks无法编译运行_C++编译期多态与运行期多态

作者:melonstreet链接:https://www.cnblogs.com/QG-whz/p/5132745.html阅读目录前言运行期多态编译期多态运行期多态与编译期多态优缺点分析运行期多态优点运行期多态缺点编译期多态缺点关于显式接口与隐式接口前言今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合,其中泛型编程与基于它的STL是C++发展中...

weixin_39628041的博客 93

C++多态、虚函数、虚函数表、编译期、运行期、静态、动态的理解

关于C++多态1. 多态分为静态多态和动态多态1.1 静态多态1.1.1函数重载1.1.2模板1.1.3静态多态总结1.2 动态多态:在运行时期才能决定函数行为1.2.1先讲一些储备知识,不然初学者听着迷糊1.2.2 多态的体现:1.2.3 动态的体现 1. 多态分为静态多态和动态多态 1.1 静态多态 静态多态是编译期决定的:在编译期间就决定了行为,也就是在运行到静态多态的时候函数的执行流程都一样 包括两种:函数重载和模板 1.1.1函数重载 函数重载:函数名相同且参数列表不同称为函数重载 静态多态体现

Go_bro的博客 2002

C++ 编译器多态与运行时多态

前言 今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合,其中泛型编程与基于它的STL是C++发展中最为出彩的那部分。在面向对象C++编程中,多态是OO三大特性之一,这种多态称为运行期多态,也称为动态多态;在泛型编程中,多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态或静态多态。 运行期多态 运行期多态的设计思想要归结到类继承体系的设计上去。对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些

bob的博客 1075
上一篇: 归一化函数normalize详解
下一篇: 构造函数为什么不能是虚函数
DP323
博客等级 码龄9年 201粉丝 33原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值