接上文。
虚函数、虚表在没有实例的情况下是无法从语法层面进行访问的。
那么其到底有没有生成呢?

#include<iostream>
using namespace std;class A
{
private:int x;long long xy;int y;public:virtual void f1(void){cout<<"A::f1"<<endl;}virtual void f2(void){cout<<"A::f2"<<endl;}
};
class B
{
private:int x;long long xy;int y;public:virtual void f1(void){cout<<"B::f1"<<endl;}virtual void f2(void){cout<<"B::f2"<<endl;}
};
class C
{
private:int x;long long xy;int y;public:virtual void f1(void){cout<<"C::f1"<<endl;}virtual void f2(void){cout<<"C::f2"<<endl;}
};
class D
{
private:int x;long long xy;int y;public:virtual void f1(void){cout<<"D::f1"<<endl;}virtual void f2(void){cout<<"D::f2"<<endl;}
};void normal_func1(){};
void normal_func2(){};
void normal_func3(){};int global_int = 0;
int global_uni;int main()
{static int static_int = 0;cout<<"(long*)normal_func1   "<<(long*)(normal_func1)<<endl;cout<<"(long*)normal_func2   "<<(long*)(normal_func2)<<endl;cout<<"(long*)normal_func3   "<<(long*)(normal_func3)<<endl;cout<<"(long*)(&global_int)  "<<(long*)(&global_int)<<endl;cout<<"(long*)(&static_int)  "<<(long*)(&static_int)<<endl;cout<<"(long*)(&global_uni)  "<<(long*)(&global_uni)<<endl;cout<<"global_uni            "<<         global_uni<<endl;B virtual_instance1;A virtual_instance0;D virtual_instance3;cout<<endl<<endl<<"虚函数相关: "<<endl<<endl;cout << "(long*)(&virtual_instance0)             " << (long*)(&virtual_instance0) << endl;cout << "(long*)(&virtual_instance1)             " << (long*)(&virtual_instance1) << endl;cout << "(long*)(&virtual_instance3)             " << (long*)(&virtual_instance3) << endl;cout << "(long*)*(long*)(&virtual_instance0)     " << (long*)*(long*)(&virtual_instance0) << endl;cout << "(long*)*(long*)(&virtual_instance1)     " << (long*)*(long*)(&virtual_instance1) << endl;cout << "(long*)*(long*)(&virtual_instance3)     " << (long*)*(long*)(&virtual_instance3) << endl;cout << "*(long*)*(long*)(&virtual_instance0)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance0) << endl;cout << "*(long*)*(long*)(&virtual_instance1)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance1) << endl;cout << "*(long*)*(long*)(&virtual_instance3)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance3) << endl;A virtual_instance00;int x = 0;cin>>x;if(x){C *pC = new C();
//        C *pC = (C*)new D();}cout << "(long*)(&virtual_instance00)            " << (long*)(&virtual_instance00) << endl;cout << "(long*)*(long*)(&virtual_instance00)    " << (long*)*(long*)(&virtual_instance00) << endl;cout << "*(long*)*(long*)(&virtual_instance00)   " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance00) << endl;cout << "(long*)(&virtual_instance0)             " << (long*)(&virtual_instance0) << endl;cout << "(long*)(&virtual_instance1)             " << (long*)(&virtual_instance1) << endl;cout << "(long*)(&virtual_instance3)             " << (long*)(&virtual_instance3) << endl;cout << "(long*)*(long*)(&virtual_instance0)     " << (long*)*(long*)(&virtual_instance0) << endl;cout << "(long*)*(long*)(&virtual_instance1)     " << (long*)*(long*)(&virtual_instance1) << endl;cout << "(long*)*(long*)(&virtual_instance3)     " << (long*)*(long*)(&virtual_instance3) << endl;cout << "*(long*)*(long*)(&virtual_instance0)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance0) << endl;cout << "*(long*)*(long*)(&virtual_instance1)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance1) << endl;cout << "*(long*)*(long*)(&virtual_instance3)    " << hex<<"0x"<<*(long*)*(long*)(&virtual_instance3) << endl;typedef void(*Fun)(void);Fun pFunc1, pFunc2, pFunc3;pFunc1 = (Fun)*((long*)*(long*)(&virtual_instance0));pFunc1();pFunc2 = (Fun)*((long*)*(long*)(&virtual_instance1) + 1);pFunc2();pFunc3 = (Fun)*((long*)*(long*)(&virtual_instance3) + 1);pFunc3();return 0;
}

输出:

(long*)normal_func1   0x55e10f66bcfa
(long*)normal_func2   0x55e10f66bd01
(long*)normal_func3   0x55e10f66bd08
(long*)(&global_int)  0x55e10f86e25c
(long*)(&static_int)  0x55e10f86e268
(long*)(&global_uni)  0x55e10f86e260
global_uni            0虚函数相关: (long*)(&virtual_instance0)             0x7ffcaa24d2e0
(long*)(&virtual_instance1)             0x7ffcaa24d2c0
(long*)(&virtual_instance3)             0x7ffcaa24d300
(long*)*(long*)(&virtual_instance0)     0x55e10f86dd18
(long*)*(long*)(&virtual_instance1)     0x55e10f86dcf8
(long*)*(long*)(&virtual_instance3)     0x55e10f86dcd8
*(long*)*(long*)(&virtual_instance0)    0x55e10f66c782
*(long*)*(long*)(&virtual_instance1)    0x55e10f66c7f2
*(long*)*(long*)(&virtual_instance3)    0x55e10f66c862

等待cin>>阻塞中。
整理:

可以看到,A::f1()-B::f1()-D::f1()之间的地址差,有个两倍的差距。如果将代码中的

  if(x){C *pC = new C();
//        C *pC = (C*)new D();}

C *pC = new C(); 删除,用下面一句,则A::f1()-B::f1()-D::f1()之间的地址差是一致的。

结论:
1 . 根据代码中是否出现实例化代码(不管有没有运行到这个地方),决定是否生成虚函数。
2 . 虚表的生成顺序与类虚函数的生成顺序正好相反,猜测是编译器使用类似栈的结构,每次生成类的虚函数都会入栈(应该是按类定义的顺序?)。
3 . 如果没有出现实例化的代码,即使有类似"C* pC;"的代码,也不会生成虚函数与虚表。
4 . 无法修改虚表,若强行修改会出现段错误。

新的问题:
1 . 全局变量、局部static变量的出现顺序似乎只与其定义的顺序有关。且未初始化的全局变量、局部static变量似乎也是与其放在一块,并没有分开放置,是因为直接生成的可执行文件吗(链接库就会分开以节省空间?)?还是说有不同的实现?
2 . Ubuntu下64位的情况下,虚表是在全局区之前、虚函数之后,虚函数是在普通函数之后;但是在windows下其地址反而是最高的,堆空间的地址好像也没有什么规律。

虚函数、虚表的生成,虚表的修改相关推荐

  1. C++虚函数的实现方式(虚表+虚指针)

    虚函数表实现原理 虚函数的实现是由两个部分组成的,虚函数指针与虚函数表. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 存在虚函数的类都有一个一维的虚函数表叫做虚表.每一个类 ...

  2. C++ 虚函数和虚表

    几篇写的不错的文章,本文是整合了这几篇文章,感谢这些大佬 https://www.jianshu.com/p/00dc0d939119 https://www.cnblogs.com/hushpa/p ...

  3. 详解虚函数的实现过程之初探虚表(1)

    空对象它有一字节的大小,在没有任何成员变量但是却有虚函数的对象里,它的大小是四个字节,这是为什么呢? 因为含有虚函数的对象里,对象的起始地址往后四个字节其实是 一个指针,它指向了一个数组,这个数组的元 ...

  4. C++中虚函数、虚指针和虚表详解

    关于虚函数的背景知识 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 存在虚函数的类都有一个一维的虚函数表叫做虚表.每一个类的对象都有一个指向虚表开始的虚指针.虚表是和类对应的 ...

  5. 虚函数,虚指针和虚表详解

    关于虚函数的背景知识 1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 2. 存在虚函数的类都有一个一维的虚函数表叫做虚表.每一个类的对象都有一个指向虚表开始的虚指针.虚表 ...

  6. 虚函数、虚指针和虚表

    虚函数.虚指针和虚表 http://eriol.iteye.com/blog/1167737 关于虚函数的背景知识 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 存在虚函数的 ...

  7. 虚函数,虚表深度剖析

    面向对象,从单一的类开始说起. class A { private:int m_a;int m_b; }; 这个类中有两个成员变量,都是int类型,所以这个类在内存中占用多大的内存空间呢? sizeo ...

  8. C++_虚继承_虚函数_纯虚函数(多继承的二义性,多态)

    基本信息 每一个类都有一个虚表,以及虚表指针; 虚表的内容是编译器决定的,虚表中用于存放虚函数的指针, 程序运行时的类型信息等; 每个多态对象都存放着一个指向当前类型的虚表的指针, 该指针在构造函数中 ...

  9. 虚函数、纯虚函数、虚继承、多继承

    来源:http://www.tnove.com/?p=57 C++的一个特征是多太,其中多态主要表现在 1.编译时多态  函数overload实现 2.运行是多态  虚函数override实现 其中虚 ...

  10. 什么情况下会用到虚方法(虚函数)?它与接口有什么不同?

    面试的时候遇到有这么一题:您在什么情况下会用到虚方法(虚函数)?它与接口有什么不同? 当不同的人面对这个问题的时候应该是有不同的反应,因为每个人对以上提到的知识点的理解程度不同.绝对有人迷惑,也有人似 ...

最新文章

  1. npoi导出execl源码,vs2008实现,包括using库
  2. Openstack 实战讲解之-----06-计算节点配置
  3. mysql生成100000个数据并检验索引的效果
  4. 005 定位控件输入call
  5. echart移上去显示内容_echarts如何移动到柱状图上显示自己想显示的提示信息
  6. 浅谈App对我们行业门户网站的作用
  7. async/await
  8. c++层次遍历_数据结构与算法,弄懂图的两种遍历方式
  9. Android 中文件类型与MIME的匹配表
  10. C#笔记16 多线程和同步
  11. java jdk9_jdk9下载-jdk9下载9.0.4 官方最新版-西西软件下载
  12. 网络历史之金融投资三剑客0
  13. 『IT视界』 [互联网]联想裁员千人不影响国内业务 每年节约2.5亿
  14. 基于Basys2的数码管动态扫描module(verilog)的模块化设计
  15. [Python知识图谱] 二.哈工大pyltp词性标注、命名实体识别、依存句法分析和语义角色标注
  16. KVM安装+vlan配置(超详细)
  17. 中英文数字混合的复合格式处理
  18. D38 463. Island Perimeter
  19. Redis——Redis事务性原理
  20. MySQL死锁产生的原因和解决方法

热门文章

  1. win11系统搭建FTP服务器超详细流程
  2. 018脑电图癫痫检测与预测算法综述(2014)
  3. 基于数据挖掘的客户流失分析案例
  4. 重庆市计算机专业高考试题,职业高中高考计算机专业试卷4
  5. 白皮书:InfiniBand简介
  6. unity android 震动,unity 调用android的震动
  7. 手把手教你实现小程序中的自定义组件
  8. 阿里巴巴内推电话面试
  9. 使用python编写的落网电台下载工具
  10. ADC0832的AD模数转换原理及编程