C++ 多态性机制初探

C++多态性:虚函数的调用原理 C++多态性:虚函数的调用原理多态性给我们带来了好处:多态使得我们可以通过基类的引用或指针来指明一个对象(包含其派生类的对象),当调用函数时可以自动判断调用的是哪个对象的函数。一个函数说明为虚函数,表明在继承的类中重载这个函数时,当调用这个函数时应当查看以确定调用哪个对象的这个函数。普通函数的处理:一个特定的函数都会映射到特定的代码,无论时编译阶段还是连接阶段,编译器都能计算出这个函数 阅读详情
多态性 (polymorphism) 是面向对象编程的基本特征之一。而在 C++ 中,多态性通过虚函数 (virtual function) 来实现。我们来看一段简单的代码:

#include <iostream>
using namespace std;

class Base
{
int a;
public:
virtual void fun1() {cout<<"Base::fun1()"<<endl;}
virtual void fun2() {cout<<"Base::fun2()"<<endl;}
virtual void fun3() {cout<<"Base::fun3()"<<endl;}
};

class A:public Base
{
int a;
public:
void fun1() {cout<<"A::fun1()"<<endl;}
void fun2() {cout<<"A::fun2()"<<endl;}
};

void foo (Base& obj)
{
obj.fun1();
obj.fun2();
obj.fun3();
}

int main()
{
Base b;
A a;
foo(b);
foo(a);
}

运行结果为:
Base::fun1()
Base::fun2()
Base::fun3()
A::fun1()
A::fun2()
Base::fun3()

仅通过基类的接口,程序调用了正确的函数,它就好像知道我们输入的对象的类型一样!

那么,编译器是如何知道正确代码的位置的呢?其实,编译器在编译时并不知道要调用的函数体的正确位置,但它插入了一段能找到正确的函数体的代码。这称之为 晚捆绑 (late binding) 或 运行时捆绑 (runtime binding) 技术。

通过virtual 关键字创建虚函数能引发晚捆绑, 编译器在幕后完成了实现晚捆绑的必要机制。它对每个包含虚函数的类创建一个表(称为VTABLE),用于放置虚函数的地址。在每个包含虚函数的类中,编译器秘密地放置了一个称之为vpointer(缩写为VPTR)的指针,指向这个对象的VTABLE。所以无论这个对象包含一个或是多少虚函数,编译器都只放置一个VPTR即可。VPTR由编译器在构造函数中秘密地插入的代码来完成初始化,指向相应的VTABLE,这样对象就“知道”自己是什么类型了。VPTR都在对象的相同位置,常常是对象的开头。这样,编译器可以容易地找到对象的VTABLE并获取函数体的地址。

如果我们用sizeof查看前面Base类的长度,我们就会发现,它的长度不仅仅是一个int的长度,而是增加了刚好是一个void指针的长度(在我的机器里面,一个int占4个字节,一个void指针占4个字节,这样正好类Base的长度为8个字节)。

每当创建一个包含虚函数的类或从包含虚函数的类派生一个类时,编译器就为这个类创建一个唯一的VTABLE。在VTABLE中,放置了这个类中或是它的基类中所有虚函数的地址,这些虚函数的顺序都是一样的,所以通过偏移量可以容易地找到所需的函数体的地址。假如在派生类中没有对在基类中的某个虚函数进行重写(overriding),那末还使用基类的这个虚函数的地址(正如上面的程序结果所示)。

至今为止,一切顺利。下面,我们的试验开始了。

就目前得知的,我们可以试探着通过自己的代码来调用虚函数,也就是说我们要找寻一下编译器秘密地插入的那段能找到正确函数体的代码的足迹。

如果我们有一个Base指针作为接口,它一定指向一个Base或由Base派生的对象,或者是A,或者是其它什么。这无关紧要,因为VPTR的位置都一样,一般都在对象的开头。如果是这样的话,那么包含有虚函数的对象的指针,例如Base指针,指向的位置恰恰是另一个指针——VPTR。VPTR指向的VTABLE其实就是一个函数指针的数组,现在,VPTR正指向它的第一个元素,那是一个函数指针。如果VPTR向后偏移一个Void指针长度的话,那么它应该指向了VTABLE中的第二个函数指针了。

这看来就像是一个指针连成的链,我们得从当前指针获取它指向的下一个指针,这样我们才能“顺藤摸瓜”。那么,我来介绍一个函数:

void *getp (void* p)
{
return (void*)*(unsigned long*)p;
}

我们不考虑它漂亮与否,我们只是试验。getp() 可以从当前指针获取它指向的下一个指针。如果我们能找到函数体的地址,用什么来存储它呢?我想应该用一个函数指针:

typedef void (*fun)();

它与Base中的三个虚函数相似,为了简单我们不要任何输入和返回,我们只要知道它实际上被执行了即可。

然后,我们负责“摸瓜”的函数登场了:

fun getfun (Base* obj, unsigned long off)
{
void *vptr = getp(obj);

unsigned char *p = (unsigned char *)vptr;
p += sizeof(void*) * off;

return (fun)getp(p);
}

第一个参数是Base指针,我们可以输入Base或是Base派生对象的指针。第二个参数是VTABLE偏移量,偏移量如果是0那么对应fun1(),如果是1对应fun2()。getfun() 返回的是fun类型函数指针,我们上面定义的那个。可以看到,函数首先就对Base指针调用了一次getp(),这样得到了vptr这个指针,然后用一个unsigned char指针运算偏移量,得到的结果再次输入getp(),这次得到的就应该是正确的函数体的位置了。

那么它到底能不能正确工作呢?我们修改main() 来测试一下:

int main()
{
Base *p = new A;

fun f = getfun(p, 0);
(*f)();
f = getfun(p, 1);
(*f)();
f = getfun(p, 2);
(*f)();

delete p;
}

激动人心的时刻到来了,让我们运行它!

运行结果为:
A::fun1()
A::fun2()
Base::fun3()

至此,我们真的成功了。通过我们的方法,我们获取了对象的VPTR,在它的体外执行了它的虚函数。

C++多态性与动态绑定的深入探讨 本文深入探讨了C++编程语言中的多态性概念,特别是静态多态性和动态多态性的实现方式。通过对象到类的绑定实现静态多态性,以及利用虚函数和纯虚函数实现动态多态性的过程被详细解析。文中还讨论了接口与实现解耦的概念,并展示了如何通过C++的特性来静态解耦接口与实现。此外,通过代码示例,文章阐述了虚拟函数如何在运行时实现方法的动态选择。 阅读详情

相关推荐

OpenBCI脑电数据处理实战:用MNE库从Raw对象到可视化分析全流程

本文提供了使用MNE-Python库处理OpenBCI脑电数据的完整实战指南。从通过BrainFlow库获取原始数据流、创建核心的Raw对象,到进行工频滤波、带通滤波等关键预处理步骤,最后实现时域信号、功率谱密度及地形图等多种专业可视化分析,手把手教你完成脑机接口数据处理的全流程。

gin88的博客 369

C++——多态性实现机制

C++的多态性实现机制剖析1. 多态性和虚函数#include <iostream.h> class animal { public: void sleep() { cout<<"animal sleep"<<endl; } void breathe() { cout<<"animal breathe"<<endl;

Fortune favors the dream of attention. 53万+

深度学习之常用算子介绍

打开 onnx 模型图,可以看到它是一个有向无环图。除了 Input、Output ,其他都是算子(是操作,而不是节点)在ONNX(Open Neural Network Exchange)模型中,除了输入和输出,其他都是算子(Operations)。算子是表示神经网络模型中的不同操作或层的元素。一个ONNX模型由一系列算子组成,通过连接这些算子来定义模型的计算流程。

ueke1的博客 8460

什么是多态?实现多态的机制是什么?

面试官:什么是多态呢? 猪队友:多种形态,气体,液体,固体~ 面试官:go out! now! 到底什么是多态呢? 官方说: 接口的多种不同的实现方式即为多态。 多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术。 我们在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确...

Mr.SSY的博客 1万+

Codex CLI 的多模型切换实战:如何在中转 API 环境下灵活选择最佳模型

本文详细介绍了在Codex CLI中实现多模型切换的实战技巧,重点解析了如何在中转API环境下灵活选择最佳AI模型。通过配置Node.js环境和智能路由策略,开发者可以根据任务类型、编程语言和成本考量,在GPT-5、Claude和DeepSeek等模型间高效切换,提升代码生成、审查和优化的效率。

weixin_29291185的博客 836

提示libfakeroot.so或libfakeroot-sysv.so出错处理方法

嵌入式Linux、Buildroot交叉编译出现fakeroot问题处理方法。

阿xin*的嵌入式AI 1443

Java面试题——什么是多态机制

什么是多态机制 一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须由程序运行期间才能决定,这就是多态性 多态性可以分为编译时多态和运行时多态。 编译时多态:主要是指方法的重载,它是根据参数列表的不同来区分不同的函数 运行时多态:在运行时谈不上多态,而运行时多态是动态的,它是通过动态绑定来实现,也就是我们说的多态性 多态的实现 Java实现多态有三个必要条件:继承、重写(覆盖)、向上转型 继承:在多态中必须存在有继承关系的子类和父类 重写:子类对父类中某些方法

clearLB的博客 1188

【应用】OpenClaw玩转有道云笔记

功能名称核心原理实操示例(直接复制可用)实操避坑+补充说明网页剪藏插件自动抓取网页正文、下载图片,通过 API 发送到你的有道云笔记,内联图片避免防盗链失效帮我把这个网页剪藏到云笔记:https://example.com/article1. 避坑:知乎、公众号等需登录的网站,先在浏览器登录再剪藏;2. 原理:自动过滤广告,只留正文;3. Twitter/X 剪藏需额外配置 APIFY_API_TOKEN(见1.2.4)创建笔记。

海兰 716

多态实现的机制

什么是多态? 多态是C++编程时的一种特性,多态性即是对一个接口的多种实现。多态可以分为静多态和动多态。所谓静多态就好比函数重载、模板,静多态是在函数编译阶段就决定调用机制,即在编译连接阶段就将函数的入口地址给出。而动多态是在程序运行的时候才决定调用机制。下面我们主要来讨论动多态。 首先来了解一些多态的基本知识: 在类中用virtual关键字声明的函数叫做虚函数。 存在虚函数的类都有一...

magic_world_wow的博客 2160

相机Camera日志分析之二:高通CamX架构对应Google原生Camera HAL3架构的标准API接口一级日志详细分析注释

【思维决定成长高度】当前讲述的是Camera领域log分析梯度分级讲解,讲究的是一种分析技巧,分析思维,一种感悟。技术路线的提升空间,需要更多开发技巧和开发学习能力去提升。技术大拿分析问题,可以从日志快速定位问题并解决问题,有充分的时间去学习更多知识,成长速度极快。同一起跑线,学习能力,开发效率等等都决定了程序员的成长提升空间。记得我毕业三年,同学之间的差距无限拉大,一些人还在几千块薪水,你已经是他的四五倍了,人与人的差距就是短短几年就拉开了。

429

我用 Python 监听了自己的键盘,生成击键热力图,看看每天到底在“摸鱼”还是“搬砖”?

数据采集(监听)、持久化(I/O)与可视化展示,必须是三个完全独立的模块,这符合单一职责原则。在多线程读写 Python 字典时,锁住的时间要尽可能短,防止 I/O 线程把高频的监听线程阻塞住。这类涉及底层的代码与“键盘记录木马”只有一线之隔。永远不要把击键记录通过网络上传,所有数据必须localhost消化。人脑对枯燥的 JSON 日志是不敏感的,但对颜色和空间极其敏感。这也是为什么 Prometheus + Grafana 是标配。使用ctypes。

BUG猿的博客 193

c++多态实现的机制

1 什么是多态? 多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。 2 实现机制 举一个例子: #include class animal { public: void sleep() { cout } void breathe() { cout } };

zyq0335的专栏 4万+

msfvenom制作windows/linux/android/ios木马

msfvenom选项如下 -p, --payload<payload> 指定 payload(攻击荷载)。如果使用自定义payload,请使用'-'或者stdin指定。 -l, --list [module_typel列出指定模块的所有可用资源。模块类型包括:payloads, encoders, nops, all -n, --nopsled <length>为payload预先指定一个NOP滑动长度。 -f, --format <format>指定输出格式(使

Cwillchris的博客 2734

C++多态性机制初探

作为面向对象编程的四大特征(抽象、封装、继承和多态)之一的多态性,是考察开发人员对面向对象的基础掌握程度的有力知识点。面试中也经常被问到像这样的问题:请简述一下什么是多态?C++多态的实现机制是什么?等等之类。今天我们就来小谈一下C++的多态机制。    首先,我们先开宗明义:在C++中,多态性通过虚函数 (virtual function) 来实现。    那么什么又是虚函数呢?有些文章又说:虚

wjlkoorey的专栏 336

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

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

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C++之多态性

1.初探多态性 在面向对象方法中,所谓多态性就是不同对象收到相同消息,产生不同的行为。在C++程序设计中,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,这样就可以用同一个函数名调用不同内容的函数。换言之,可以用同样的接口访问功能不同的函数,从而实现“一个接口,多种方法”。 事实上,在程序设计中经常会使用到多态性。最简单的例子就是运算符了,例如我们使用运算符+,就可以实现整型数...

studyhardi的博客 5万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++中的多态性实现原理

C++中的多态性主要通过虚函数和继承实现,允许在运行时根据对象的实际类型调用相应的方法。虚函数机制依赖于虚表(vtable)和虚指针(vptr),使得程序能够动态地选择合适的函数实现。通过使用多态性,开发者可以编写更灵活和可扩展的代码,适应不断变化的需求。虚表是一个指针数组,数组中的每个元素指向该类的虚函数的实现。每个包含虚函数的类都有一个虚表。虚表是在编译时生成的,通常在类的定义时创建。虚指针(vptr)是一个指向虚表的指针,存在于每个包含虚函数的对象中。它指向该对象所属类的虚表。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1129

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

解释 C++ 中的多态性,以及如何实现运行时多态性?

然后,在基类指针或引用指向派生类对象时,调用虚函数会根据对象的实际类型而不是指针或引用的类型来确定调用的函数版本。编译时多态性:编译时多态性是通过函数的重载和模板实现的。在main函数中,基类指针ptr分别指向了Dog和Cat对象,但调用speak()函数时会根据指向的对象类型而执行不同的实现,这就是运行时多态性的体现。这意味着通过相同的接口可以调用不同类型的对象,并且会根据对象的实际类型来执行相应的操作。C++中的多态性通过虚函数来实现,分为编译时多态性(静态多态性)和运行时多态性(动态多态性)两种。

qiuyehuanghun的博客 3272

C++ 多态性

构造函数不能定义为虚函数。而析构函数可以定义为虚函数。若析构函数为虚函数,那么当使用delete释放基类指针所指向的派生类对象时,先调用派生类的析构函数,再调用基类的析构函数。

钢铁男儿 929

C++ 虚函数与多态性

多态性 面向对象程序设计中的多态性是指向不同的对象发送同一个消息,不同对象对应同一消息产生不同行为。在程序中消息就是调用函数,不同的行为就是指不同的实现方法,即执行不同的函数体,也可以这样说就是实现了“一个接口,多种方法” ...

Chroniccandy的博客 2512

C++多态性定义、实现以及示例详细介绍

C++多态性是面向对象程序设计中的重要概念,它允许子类对象具备父类对象的方法和属性。本文将详细介绍C++多态性的定义、实现以及示例,帮助初学者更好地理解和掌握多态性。

Python966的博客 5762

C++虚函数详解&实现机制&多态性

转载:http://blog.chinaunix.net/uid-24178783-id-370328.html

我的博客 1897

C++多态性

         C++编程语言是一款应用广泛,支持多种程序设计的计算机编程语言。我们今天就会为大家详细介绍其中C++多态性的一些基本知识,以方便大家在学习过程中对此能够有一个充分的掌握。   多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphisn),字面意思多种形状。   C++多态性是通过虚函数来实现

focus leepple 480

C++中的多态性

一篇文章带你速通C++多态!

2301_77754590的博客 1946

C++的多态性和虚函数

1.作为新手学习C++的多态性,首先应该了解C++的多态性有何现实意义? 多态性的现实意义在于可以用相同的函数名来标识这些函数,达到用同样的接口访问不同功能的函数,从而实现“一个接口,多种方法”。通俗点说就是可以不用像C语言中为了求多种图形的面积而针对不同的图形各设计了一个名字独立的函数,在C++中只要设计一个专门用于求面积的函数名字即可,这个专门用于求面积的函数名字可以作为求各种图形面积...

jacket_的博客 795
上一篇: 求win32下的多线程控制台程序(c实现)
下一篇: 重新经营我的BLOG
thb28
博客等级 码龄24年 3粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值