我们大部分时候使用的多态虚表实在public继承的基础上实现的
这句话可以怎么说了?
自己简单的思考逻辑认为基类中的成员或者成员函数子类中都会重新拷贝一份,也就是如果派生类中没有定义基类的某虚函数重写但是这个**虚函数的地址已经被写实拷贝写了一份放到派生类·虚表当中了**

  • 好了,来看一下一种情况下的虚表情况吧!
  • 单继承虚表
class Base
{
public:virtual void func1(){ cout << "Base::func1" << endl;}virtual void func2(){cout << "Base::func2" << endl;}
private:  int a;
};class Derive :public Base
{
public:   virtual void func1(){cout << "Derive::func1" << endl;}virtual void func3() {cout << "Derive::func3" << endl;}virtual void func4(){cout << "Derive::func4" << endl;}
private:  int b;
};
int main()
{Base b;Derive d;return 0;
}
  • !!!看一下这里问题就出来了,和理论之中存在差别,基类子类当中的自己虚函数并没有显示出来
  • 这里是编译器的监视窗口故意隐藏了这两个函数, 也可以认为是他的一个小bug。那么我们如何查看d的虚表呢?下面我们使用代码打印出虚表中的函数。

    模拟定义一个虚表指针,来把虚表元素打印出来
class Base
{
public:virtual void func1(){ cout << "Base::func1" << endl;}virtual void func2(){cout << "Base::func2" << endl;}
private:  int a;
};class Derive :public Base
{
public:   virtual void func1(){cout << "Derive::func1" << endl;}virtual void func3() {cout << "Derive::func3" << endl;}virtual void func4(){cout << "Derive::func4" << endl;}
private:  int b;
};
typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[])
{    cout << " 虚表地址>" << vTable << endl;   for (int i = 0; vTable[i] != nullptr; ++i) {printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);        VFPTR f = vTable[i];f();   }cout << endl;
}int main()
{Base b;Derive d;VFPTR* vTableb = (VFPTR*)(*(int*)&b);   PrintVTable(vTableb);VFPTR* vTabled = (VFPTR*)(*(int*)&d);  PrintVTable(vTabled);return 0;
}

  • 思路:取出b、d对象的头4bytes,就是虚表的指针,前面我们说了虚函数表本质是一个存虚函数指针的 指针数组,这个数组最后面放了一个nullptr
  • 1.先取b的地址,强转成一个int*的指针
  • 2.再解引用取值,就取到了b对象头4bytes的值,这个值就是指向虚表的指针
  • 3.再强转成VFPTR*,因为虚表就是一个存VFPTR类型(虚函数指针类型)的数组。
  • 4.虚表指针传递给PrintVTable进行打印虚表
  • 5.需要说明的是这个打印虚表的代码经常会崩溃,因为编译器有时对虚表的处理不干净,虚表最后面没有 放nullptr,导致越界,这是编译器的问题。我们只需要点目录栏的-生成-清理解决方案,再编译就好了。
  • 多继承虚表
class Base1
{
public:  virtual void func1() {cout << "Base1::func1" << endl; } virtual void func2(){cout << "Base1::func2" << endl;}
private:int b1;
};class Base2
{
public:   virtual void func1() {cout << "Base2::func1" << endl;}virtual void func2() {cout << "Base2::func2" << endl;}
private:int b2;
};class Derive : public Base1, public Base2
{
public:   virtual void func1(){cout << "Derive::func1" << endl;}virtual void func3() { cout << "Derive::func3" << endl;}
private:    int d1;
};typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[]) {cout << " 虚表地址>" << vTable << endl;    for (int i = 0; vTable[i] != nullptr; ++i)    {printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);  VFPTR f = vTable[i];   f(); } cout << endl;
}int main() {Derive d;VFPTR* vTableb1 = (VFPTR*)(*(int*)&d); PrintVTable(vTableb1);VFPTR* vTableb2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1)));PrintVTable(vTableb2);return 0;
}



可以看出:多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中

单继承与多继承的虚函数表相关推荐

  1. C++ 面向对象(二)多态 : 虚函数、多态原理、抽象类、虚函数表、继承与虚函数表

    目录 多态 多态的概念 多态的构成条件 虚函数 虚函数的重写 协变(返回值不同) 析构函数的重写(函数名不同) final和override final override 重载, 重写, 重定义对比 ...

  2. C++ - 多继承方式会产生多个虚函数表

    1.多重继承可能产生多个虚函数表 代码示例:会产生多个虚函数表 #include <iostream> #include <string>using namespace std ...

  3. C++之多态 虚函数表

    多态 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为. 需要区分一下:1.菱形虚拟继承,是在继承方式前面加上virtual: class Person {}; class Studen ...

  4. C++虚函数表的总结

                          1. C++的多态主要是通过虚函数表来实现的: (1)编译器为每个虚基类生成一个虚函数表,但是类中只包含该虚函数表的首地址: (2)每个继承自需基类的子类都 ...

  5. 虚函数的实质——虚函数表

    目录 虚函数的实质--虚函数表 虚函数表是什么? 虚函数表长什么样? 证明了确实存在隐藏的虚函数表指针 派生类指针转换为基类类型的实质 当基类指针指向派生类对象时,虚函数表会如何变化? 虚函数的实质- ...

  6. 9-4:C++多态之单继承和多继承中的虚函数表

    文章目录 (1)单继承中的虚函数表 (2)多继承中的虚函数表 (1)单继承中的虚函数表 如下继承体系中,fun1函数重写,fun2未被重写,B类中fun3和fun4也被定义为了虚函数 #include ...

  7. C++ 多态(二) : 虚函数、静态绑定、动态绑定、单/多继承下的虚函数表

    文章目录 ⏰1.多态的原理--虚函数表

  8. 一篇文章带你学懂C++虚函数表的继承问题

    虚函数表-继承 单继承 结论: 当父类定义了虚函数时,在子类进行继承的时候会将父类的虚函数表也给继承下来所以那一些虚函数在子类中也是virtual类型的,如果要对父类中的虚函数进行重写时或添加虚函数, ...

  9. 虚函数继承与虚函数表-汇编码分析

    (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 参考:https://www.equestionanswers.com/cpp/vptr-and-vta ...

最新文章

  1. 博客非100%原创,在学习道路上,我一直站在别人肩上
  2. Pytorch CookBook
  3. 32位十六进制浮点数转换为十进制浮点数的方法
  4. JMetro版本8.6.11和11.6.11已发布
  5. 598. 范围求和 II
  6. flink 1.9 编译: flink-shaded-asm-6 找不到
  7. atlas 力矩计算_Atlas Copco基本拧紧技术
  8. 自学TP5源码(一)
  9. 使用wget下载KITTI数据集
  10. Spring Cloud 中文网
  11. matlab冲激函数的傅里叶变换,利用MATLAB对正弦,矩形脉冲函数进行傅里叶变换
  12. 第2章 先从看得到的入手,探究活动
  13. 什么是嵌入式系统?STM32能跑linux吗?
  14. Arturia V Collection 9 for mac - Arturia系列合成器合集
  15. 换了5G手机不会用5G网络?赶快来补课!
  16. dreamweaver cs5 注册码及防激活
  17. 梯度下降算法_梯度下降算法的工作原理
  18. Networkx_python 之Algorithms——Approximations and Heuristics
  19. 学习Masonry框架 - iOS
  20. 克鲁斯卡尔算法 与 普里姆算法

热门文章

  1. Java毕业设计_基于SSM的美食食谱分享网站的设计与实现
  2. gke下载_我们如何在GKE上升级Kubernetes
  3. Chatgpt聊天机器人系统开发
  4. 有趣的排序算法——Monkey King排序 详细介绍
  5. GCN-LSTM预测道路交通车辆速度 英文 Vehicle Speed Forecasting Based On GCN-LSTM Combined Model
  6. 究竟新买的手机电池第一次要充多久的电
  7. Androd studio无线调试及镜像投屏
  8. Pytorch-模型参数:named_parameters()、parameters()、state_dict()区别
  9. 面向对象基础案例(2)
  10. android和苹果内存,安卓的8G运行内存为什么与苹果3G的运行内存不能抗衡?