虚函数详细理解

c++虚函数详解 某基类中声明为virtual并在一个或多个派生类中重新定义的成员函数叫做虚函数。用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”。实现动态联编,在函数运行阶段动态的选择合适的成员函数。 在定义了虚函数后,可实现在派生类中对虚函数进行重写,从而实现统一的接口和不同的执行过程。... 阅读详情

1.虚函数的使用?

        1.1虚函数的定义

        在实现c++多态时会用到虚函数。虚函数使用的其核心目的是通过基类访问派生类定义的函数。所谓虚函数就是在基类定义一个未实现的函数名,为了提高程序的可读性,建议后代中虚函数都加上virtual关键字。一般格式:

        上述代码在基类中定义了一个test的虚函数,所有可以在其子类重新定义父类的做法这种行为成为覆盖(override),或者为重写。

        常见用法:声明基类指针,利用指针指向任意一个子类对象,调用相关的虚函数,动态绑定,由于编写代码时不能确定被调用的是基类函数还是那个派生类函数,所以被称为“”虚“”函数。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。

3.虚函数之vptr(虚指针)和vtbl(虚表)
        类在继承中的内存是如何实现管理的?

                在类的继承中,每一个class产生一堆指向virtual function的指针,放在vtbl(虚表)中。对于每一个class object 被添加了一个指针,指向相关的virtual table,这里指针称为vptr(虚指针)。

        下面我们结合上图对vptr和vtbl做进一步的讲解:

        图中定义了三个类,分别为class A、class B、class C;其中class A 是class B的基类,class B 是class C的基类。

        class A 的 公共成员中有四个函数接口,分别为虚函数 virtual void vfunc1(); virtual void vfunc2();普通成员函数void func1();void func2()。class A中有两个私有成员,分别为m_data1和m_data2。
        class B 继承了class A ,但是class B中的虚函数virtual void vfunc1()覆盖了基类的同名虚函数;此外class B的公共成员中还有一个属于自己的函数 void func2(),注意,这里面的函数func2虽然与class A中的函数func2同名,但是他们是互补相关的两个函数,也不存在谁覆盖谁,因为他们并没有将该同名函数申明为virture function(虚函数),所以class B的对象在调用void func2()的时候,它只能调用到class B自身公共成员函数中的void func2()函数,而无法调用到class A 中的void func2()函数。 对由于class B中的私有成员只有一个m_data3。
        class C继承了class B,但是但是class C中的虚函数virtual void vfunc1()覆盖了基类class B中的同名虚函数;此外存在一个公共成员函数:void func2(),其调用原理,参考上一段文字(在此处就不做详细说明了)。

        现在我们知道了A、B、C这三个类的继承关系,以及各自所拥有的公有成员、私有成员以及各自的virtual function 。那么我们接下来就来谈谈,各自对象的虚指针和虚表。

        从图的左上角可以看到,当class中有虚函数时,那么他所创建的对象将会多出一个指针(如图中的黑点所示为一个指针),这也是为什么类中有虚函数比类中没有虚函数在进行对象所占字节的测试时,会多出4个字节,而这多出的四个字节其实就是vptr(虚指针);在图中虚指针对应的地址为0x409004,对于对象a的成分除了包括一个vptr(虚指针)外,还包函两个数据成员               m_data1、m_data2. 对象a通过虚指针指向虚表(A vtbl),表中放的都是函数指针,指向虚函数。从class A中可以看出class A有两个虚函数,所以vtbl中有两个虚指针,分别指向对应的虚函数。(注意同种相同颜色的框框)。

        此处补充一下:对于图中给出的三个类(class A,class B,class C)他们一共有8个函数。对应的四个普通成员函数和四个虚函数,必须要明白的一点是,如果基类中有虚函数,那么子类中一定有虚函数,因为子类继承了基类的成份。并且虚指针只能调用虚函数,而不能调用普通成员函数。

 对于B的对象b,因为class B继承了class A,而class A中有虚函数,那么刚才我们说了继承时,由于子类继承了基类的成分,所以对象b一定也有一个虚指针,指向对应的虚函数。而对象b中由于是继承了基类A,所以对象b的成分按照顺序将会包含:一个虚指针,对象A的m_data1,m_data2(基基类的成份),然后才到自身的m_data3。

        对于C的对象c,他的成分同样是按顺序包括:一个虚指针,类A的m_data1,m_data2,类B的m_data3,和自身的m_data1、m_data4.

        由于是虚指针,各自的虚指针(vptr)只会指向各自对象对应的虚表( vtbl ) ,对于class A的对象a的虚指针指向的虚表有两个虚函数分别为A::vfunc1()和A::vfunc2()。这个比较好理解。

        那么对于class B的对象b,它的虚指针呢。因为class B是class A的子类,子类将会继承基类的成分,而基类有两个虚函数vfunc1()和vfunc2(),这两个虚函数都属于基类的成分,所以继承时都需要继承,但是class B的虚函数virtual void vfunc1()将基类的同名虚函数覆盖掉了,那么实际上对象b只有两个虚函数,分别为自身的虚函数vfunc1(),和来自基类继承的虚函数vfun2()。

   对于class C的对象c而言,其原理可以参考对象b,但是需要说明的一点是,由于class C继承了class B,而class B 又继承了class A,虽然class B中没有写出虚函数vfunc2(),但是实际上class B中时包含了class A的的虚函数vfunc2()的成分的。又因为class C,继承了class B,这时候我们从上面的图中左下角可以看到,class C的对象中其实上是包含了class B从class A中继承过来的成分。所以此时对于class C的对象c来说,它也是包含了两个虚函数的,分别为自身的虚函数vfunc1(),和A::vfunc2()。

4.虚函数与纯虚函数
                首先:强调一个概念

        定义一个函数为虚函数,不代表函数为不被实现的函数。

        定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。

        定义一个函数为纯虚函数,才代表函数没有被实现。

        定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。

4.1纯虚函数
4.1.1定义

        纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加 =0:

virtual void funtion1()=0
4.1.2引入原因

        在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

        为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

        声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。

        纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。

        定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。

4.2抽象类
包含纯虚函数的类称为抽象类。

                抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。

4.2.1抽象类的作用

         抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。

4.2.2使用抽象类时注意:

        抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。
抽象类是不能定义对象的。

一文详解C++的虚函数 在 C++ 中,虚函数(Virtual Function)是实现多态性(Polymorphism)的核心机制,它允许派生类重写基类的函数,并在运行时根据对象的实际类型调用相应的函数版本。 阅读详情

相关推荐

告别复杂配置:利用原生DDNS实现IPv6直连群晖的极简指南

本文详细介绍了如何利用原生DDNS实现IPv6直连群晖NAS的极简方法,告别复杂配置。从检查IPv6网络环境、路由器防火墙设置到群晖DDNS配置,一步步指导用户完成设置,并分享移动网络下的使用体验和安全防护建议,帮助用户轻松实现远程访问。

weixin_30918633的博客 414

虚函数详解

c++虚函数

qq_25427995的博客 7736

基于Simulink的直流电机双闭环调速系统抗扰动仿真与参数优化

本文详细介绍了基于Simulink的直流电机双闭环调速系统仿真与参数优化方法。通过构建转速外环与电流内环的仿真模型,阐述了利用工程设计法整定PI参数的核心步骤,并重点探讨了如何优化系统参数以增强其抗负载突变等扰动的能力,实现快速、平稳的调速性能。

weixin_29061997的博客 193

虚函数

文章目录虚函数虚函数的定义虚函数使用的注意事项虚表什么是虚表图解说明虚表的四种情况一般继承(无虚函数覆盖)一般继承(有虚函数覆盖)多重继承(无虚函数覆盖)多重继承(由虚函数覆盖) 虚函数虚函数的定义 虚函数是一个类的成员函数,它的定义语法如下: 特别注意: 当一个类的一个成员函数被定义为虚函数时,则由该类派生出来的所有派生类中,该函数始终保持虚函数的特征 当在派生类中重新定义虚函数时,不必加关...

weixin_38607041的博客 1万+

【水文】calico-node 启动失败 Init:CrashLoopBackOff

Defaulted container "calico-node" out of: calico-node, upgrade-ipam (init), install-cni (init), mount-bpffs (init) Error from server (BadRequest): container "calico-node" in pod "calico-node-4j7td" is waiting to start: PodInitializing

大健的日常的博客 1万+

rk3568 RGMII KSZ8795 MAC TO MAC

参考《Rockchip_Developer_Guide_Linux_MAC_TO_MAC_CN.pdf》

明天乌儿会歌唱 6493

【C++ | 虚函数】虚函数详解 及 例子代码演示(包含虚函数使用、动态绑定、虚函数表、虚表指针)

👉本文介绍了C++的虚函数,包括虚函数的定义、重写,动态绑定、虚函数表、虚表指针等内容。

wkd_007的博客 7098

生成模型实战 | StyleGAN详解与实现

StyleGAN 能够生成非常高分辨率人脸图像的关键在于,在增加分辨率的步骤中逐步增加生成网络和判别网络的复杂性,以便在每一步中,两个模型都可以很好地完成任务。我们学习了如何通过确保每个分辨率的特征由一个独立的输入(称为风格向量)来控制,从而操纵生成图像的风格,以及如何通过将图像之间的风格进行交换来操作不同图像的风格。

盼小辉丶的博客 7623

对虚函数的理解

1.           从基类指针或基类引用获得派生类的行为的最好方法是通过虚函数机制。      虚函数是动态绑定的,也就是说,使用指向派生对象的基类指针和引用调用一个virtual函数时,究竟调用哪一份函数实现代码,取决于发出调用的那个对象的动态类型。     简而言之就是用父类的指针或引用 指向 其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种

享受开发技术,享受计算机科学 1045

手把手教你学SOC芯片架构--NoC(片上网络,Network on Chip)全方位解析

​、​。

MHD0815的博客 865

深度解读 ABAP CDS View 中的 @Analytics.dataCategory: #FACT 注解

注解在 ABAP CDS View 中具有重要意义。它不仅定义了当前视图在数据模型中的角色,还为后续的分析和报告奠定了基础。在实际开发中,通过合理使用这一注解,可以显著提升数据模型的可用性和系统性能。无论是简单的 KPI 展示还是复杂的多维分析,这一注解都能发挥关键作用。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 788

【C++】深入理解C++虚函数与纯虚函数

虚函数是在基类中使用关键字virtual声明的成员函数,它允许派生类对其进行重写(Override),实现运行时多态。当通过基类指针或引用调用虚函数时,实际调用的是对象类型对应的派生类中的函数,这个过程称为动态绑定(Dynamic Binding)或晚绑定(Late Binding)。虚函数重写指的是派生类中提供一个函数版本,该版本与基类中具有相同名称、相同返回类型和相同参数列表的虚函数相匹配。通过这种方式,派生类可以提供自己特定的实现,替换或扩展基类的行为。

Colorful___的博客 2万+

【ComfyUI 基础教程】ComfyUI 局部重绘工作流教程

本篇指南将带你了解 ComfyUI 中的局部重绘工作流,并带你完成一个局部重绘的示例,以及遮罩编辑器的使用等。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 303

深入理解虚函数

前言在C++中,在基类中被声明为virtual并在在一个或多个派生类中被重新定义的成员函数就是虚函数。基本格式如下:virtual (return_type) (func_name) (arg) {function body;}我们可以通过指向派生类的基类指针或引用来调用派生类中同名覆盖的成员函数。如下代码:class A { public: virtual void pri

Yates Law的博客 428

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

虚函数的深入理解

声明:本文载自以下链接http://www.cnblogs.com/taoxu0903/archive/2008/02/04/1064234.html个人认为这篇文章的理解是比较深入的!收藏下来,仔细研究下!理解虚函数( virtual function )的几个关键点:1.       理解早绑定(early binding)、晚绑定(late binding

Yasin Lee 1050

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

通过程序理解虚函数的实现与访问

#include<iostream> using namespace std; class Poin //定义基类 { public: Poin(double a = 0, double b = 0) { x = a, y = b; } virtual double area() //必须在基类中必须定义虚函数, //在派生类中重新定...

铩羽 193

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

我所理解的 c++虚函数

我理解的虚函数 曾经在微博看到大牛说道,面试c++能力,虚函数能摆谈一个小时就是不错的。 先列出问题。 1. c++中的关键词角度 Virtual 函数,纯虚函数,虚继承 。 2. 面向c++对象模型角度 看待虚函数 3. 虚函数的使用角度         结合ctor ,dtor等等 4. 高级主题,简要说明虚函数的优点、缺点 5.高级主题,请举例说

珍爱生命 远离C++ 1132

虚函数与多态的理解

虚函数与多态的理解 开发工具与关键技术:C++、VisualStudio 作者:张国军 撰写时间:2019年04月10日 多态性(Polymorphism)是指一个名字,多种语义;或界面相同,多种实现。 重载函数是多态性的一种简单形式。 虚函数允许函数调用与函数体的联系在运行时才进行,称为动态联编。 被关键字 virtual 修饰的成员函数称为虚函数 实现运行时多态的关键首先是要说明虚函数,另外...

weixin_44545509的博客 846

关于虚函数的理解

最近突然发现,我对虚函数的理解有些迷茫,在网上查了查,做个个简要的理解。    一般,在C++中,虚函数是用来实现基类和派生类的成员函数的。看着貌似和重载函数相类似,但是两者确实还是有些区别。  首 先,虚函数是用virtual 来修饰这个函数的。一般这样的情况就是为我们声明了这个成员函数属于虚函数,于是我们就可以在其派生类中重新定义这个函数的实现方式,当程序在运行时动态的选择合适的成员函数

lishunhai2012的专栏 554

深入理解C++ 虚函数

C++ 中的虚函数(virtual function)是面向对象编程中的一个重要概念,它允许子类重新定义从父类继承的方法。当子类对象被当作父类对象使用时,可以通过子类的方法实现来调用子类的方法,而不是父类的方法。这是因为在删除子类对象时,如果析构函数不是虚的,那么只会调用基类的析构函数,而不会调用子类的析构函数,这可能导致资源泄露。:当通过基类指针或引用调用虚函数时,实际调用的是运行时对象的实际类型所定义的函数。在子类中,可以重写(override)这个函数,即使用相同的函数名和参数列表。

A185822153的专栏 426

理解C++虚函数

转自:c++虚函数&nbsp; 大牛的文章,就是清晰,言简意赅。 前言 C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变...

mythinker2的博客 683

通过汇编角度理解虚函数!

今天通过汇编角度在次理解一下虚函数.工作环境VC6方法DEBUG 跟踪MEMORY测试程序代码 虽然是测试程序但希望大家还是养成良好习惯 不要污染命名空间测试代码:#include "iostream"using std::cout;using std::endl;class a{  int m_a;public:  a(int x):m_a(x) {}  virtua

likexin的专栏 3669

C++——深入理解虚函数和纯虚函数

C++ 作为面向对象的语言,主要有三大特性:继承、封装、多态。关于多态,简单说就是同一个函数调用,在不同对象上有不同的表现。也就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。C++ 的多态主要有两种类型:编译时多态(静态多态)和运行时多态(动态多态)。

小拉拉的博客 1511

虚函数处理理解

将下面代码改编,让D:BB()变为B:BB()#include&lt;iostream&gt; using namespace std; class B { public : int a; B(){a=1;cout&lt;&lt;"B()"&lt;&lt;endl;BB();} ~B(){cout&lt;&lt;"~B()"&lt;&lt;endl;BB();} void BBB(

JTR502的博客 309

理解虚基类、虚函数与纯虚函数的概念(转载)

引言一直以来都没有写过一篇关于概念性的文章,因为我觉得这些概念性的东西书本上都有并且说的也很详细写来也无用,今天突发奇想想写 一写,下面就和大家讨论一下虚基类、虚函数与纯虚函数,一看名字就让人很容易觉得混乱。不过不要紧待看完本文后你就会理解了。正文虚基类       在说明其作用前先看一段代码 class A{public:    int iValue;};class B:public A{...

iteye_10794的博客 147

对虚函数的初步理解

在某基类中声明为virtual 并在一个或多个派生类中被重新定义的成员函数。 用法格式:virtual 函数返回类型 函数名(参数表){函数体}。 实现了多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。 简单的例子: #pragma once #include using namespace std; class CA { public:     vi

qq_33633653的博客 277
上一篇: 继承前半部分
下一篇: 什么是进程?
chen_ever
博客等级 码龄4年 497粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值