本篇文章直入正题。 我们的类成员函数分为inline、virtual、static、normal。 **normal成员函数:**其地址和一般函数的地址没有区别,就是函数代码在内存中的真实地址,但其调用要绑定到一个实实在在的对象上。取其地址需要使用“&”运算符。 **virtual成员函数:**其地址指的是其在vtable中的位置;取其地址需要使用“&”运算符。 inline成员函数:在运行时会展开,虽然语言允许取其地址,但是没有太大意义。 static成员函数:其地址和普通全局函数的地址没有任何区别;其不依赖与类的对象而存在,也不依赖与类的对象而调用,只是作用域变成了类作用域,可以像取全局函 在C++编程中,成员函数是类的重要组成部分,它们提供了操作和访问类对象的能力。根据功能和特性,成员函数可以分为几种类型:inline、virtual、static和normal(非虚)。这篇文章将聚焦于normal成员函数和virtual成员函数在调用过程中的差异,从汇编角度进行解析。 **正常成员函数(Normal Member Function):** 正常成员函数的调用是通过对象实例来执行的,其地址代表的是函数在内存中的实际位置。这个地址可以通过“&”运算符获取。调用时,编译器会隐式地传递一个隐藏的`this`指针,指向调用该函数的对象,以便访问对象的数据成员。例如,假设有一个类`MyClass`和一个正常成员函数`func()`,调用方式可能是这样的: ```cpp MyClass obj; obj.func(); ``` 在汇编层面上,这将涉及对`obj`的内存地址的计算,然后跳转到`func()`的代码位置执行。 **虚成员函数(Virtual Member Function):** 虚函数引入了多态性,使得子类可以重写父类的行为。虚拟函数的地址实际上是指向虚函数表(Vtable)中的一个条目,而非函数代码的直接地址。Vtable是一个由编译器生成的动态数据结构,存储了类中所有虚函数的指针。当通过基类指针或引用调用虚函数时,会先查找Vtable中的对应项,然后通过该指针调用实际的函数。例如: ```cpp class Base { public: virtual void func() { /*...*/ } }; class Derived : public Base { public: void func() override { /*...*/ } }; Base* basePtr = new Derived(); basePtr->func(); // 在汇编中,会查找basePtr的Vtable并调用Derived::func() ``` 在这个例子中,即使`basePtr`指向`Derived`对象,由于`func`是虚函数,所以调用的是`Derived`版本的`func()`。 **调用默认构造函数:** 含有虚函数的类,即使没有显式定义构造函数,编译器也会提供一个默认的构造函数。这是因为每个包含虚函数的类实例都需要一个虚函数表指针(vfptr),而构造函数负责初始化这个指针。正因为构造函数在对象创建时执行,因此它不能是虚函数,否则会在对象尚未完全初始化之前尝试通过vfptr调用虚函数,导致未定义行为。 总结来说,正常成员函数的调用是直接的,而虚成员函数的调用需要通过Vtable间接完成,以实现多态性。理解这些底层机制有助于优化代码和调试,特别是在处理复杂继承关系和多态场景时。为了更深入地了解这些概念,可以通过阅读汇编代码或者编写测试用例,观察不同成员函数调用的细节。
- 粉丝: 5
- 资源: 921
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- (源码)基于MQTT协议和Docker的IoT远程监控管理系统.zip
- 高项论文写作思路之项目整体管理
- (源码)基于 ASP.NET Core 3.1 + Vue.js 的 EasyCode 后台管理系统.zip
- (源码)基于Spring和MyBatis的疫情防控管理系统.zip
- Rust 学习教程(入门到实践)
- (源码)基于Spring Boot和MyBatis的博客管理系统.zip
- 广东省省级政务信息化服务预算编制标准:软件开发服务分类及费用计算规则
- 支持IJKPlayer、Media3(EXOPlayer2)、MediaPlayer、AliPlayer实现了多功能的视频播放器
- NS3中CSMA模型介绍和数据收发流程代码分析
- (源码)基于Spring Boot和Stable Diffusion的风格化图片生成系统.zip
评论0