当前位置: 首页 > news >正文

跟我一起学习C++虚函数--第二篇

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    上一篇,我们讨论了带有虚函数的对象的内存布局情况。这一篇,主要讨论带有虚函数的类在单一继承情况下的内存布局情况。

     还是从例子入手:

#include <iostream>

using namespace std;

class Point
{
public:
    int x();
    virtual void y(){cout << "Point y" << endl;};
    virtual void print1(){cout << "Point print" << endl;};
    int _x;
};

class Point2:public Point
{
public:
    virtual void y(){ cout << "Point2 y" << endl;};
    virtual void print2(){cout << "Point2 print" << endl;};
    int _y;
};

int main()
{
    Point *p = new Point();
    Point2 *p2 = new Point2();

    /*first part*/
    cout << p2 << "\t" << &p2->_x << "\t" << &p2->_y << endl;

    /*second part*/
    typedef void (* Func)(void);
    Func pFunc = (Func)*((int *)*(int *)(p2));
    pFunc();//输出:Point2 y
    pFunc = (Func)*((int *)*(int *)(p2)+1);
    pFunc();//输出:Point print
    pFunc = (Func)*((int *)*(int *)(p2)+2);
    pFunc();//输出:Point2 print

    return 0;
}

 对与这个例子,我们从两部分讨论。

第一部分:继承情况下,对象本身(除虚函数表外)的内存布局。

         从代码中first part的输出情况,我们可以看出对象内存布局情况如下图所示:

            

        虚指针始终在对象的起始地址处,接下来是父类的成员变量,最后是子类自己的成员变量。

第二部分:继承情况下,虚函数表的内存布局。

        从代码second part的输出情况,我们可以看出虚函数表的内存布局如下图所示:

        

        编译器之所以这样安排父类和子类中虚函数的位置,说白了就是为了实现对父子类虚函数的动态绑定,因为对虚函数是通过虚表的槽位来进行调用的。举例说明:

        比如调用void y();

        编译器可能把代码:

Point *p = new Point();
p->y();
p = new Point2();
p->y();

        把所有对y()函数的调用都变成 p->vptr->vptbl[0];而Point和Point2对象的槽位0中分别是它们自己的void y()函数,因此就实现了动态绑定。类似的,对子类没有覆盖的虚函数,也可以通过同样的槽位进行调用;对子类有而父类没有的虚函数,子类对象可以用自己独有的槽位来进行调用。

 

参考文献:

        1.《深度探索C++对象模型》

转载于:https://my.oschina.net/pathenon/blog/67115

相关文章:

  • MySQL优化order by导致的 using filesort
  • 管理日志-原创理论工具--技能方格图
  • objective-c系列-NSMutableString
  • MySQL 数据库开发规范
  • 20 种提升网页速度的技巧
  • xdebug代码调试工具
  • AngularJS Toaster
  • 静态网站生成器将会成为下一个大热门
  • 二维数组举例
  • 7月上旬全球域名新增13.5万个 环比减少近29%
  • sftp详细参数说明
  • Shane版详细设计书 文档模板
  • 简比:三大电商巨头的平台、支付、物流
  • VC++ 如何让ScrollView视图显示滚动条
  • android自定义View的用法
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • JavaScript设计模式之工厂模式
  • Java知识点总结(JavaIO-打印流)
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • Redis 懒删除(lazy free)简史
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 从tcpdump抓包看TCP/IP协议
  • 从零开始在ubuntu上搭建node开发环境
  • 浮动相关
  • 基于Android乐音识别(2)
  • 前端性能优化--懒加载和预加载
  • 算法---两个栈实现一个队列
  • 通过npm或yarn自动生成vue组件
  • 原生JS动态加载JS、CSS文件及代码脚本
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (06)Hive——正则表达式
  • (3)nginx 配置(nginx.conf)
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (强烈推荐)移动端音视频从零到上手(下)
  • (转)VC++中ondraw在什么时候调用的
  • (转)创业家杂志:UCWEB天使第一步
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • (转载)(官方)UE4--图像编程----着色器开发
  • **PHP分步表单提交思路(分页表单提交)
  • .NET Core 2.1路线图
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .Net中的集合
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [2016.7.Test1] T1 三进制异或