探索c++虚函数表

c++中多态的实现

我们都知道,c++中的多态是在虚函数的基础上实现的,用指向派生类的基类指针调用派生类(或基类)中自己的成员函数。那么,具体是怎么实现的呢?

其实它是通过虚函数表来实现的,虚函数表是保存虚函数地址的一张表,若一个类中有虚函数,当程序运行时,编译器通过在虚函数表中查找相应的虚函数的地址来调用该函数。

对象的继承有如下几类:

1.单一继承

2.多重继承

3.重复继承(钻石继承)

4.虚继承

下面我们分别来看一下各种继承的内存布局:

单一继承

单一继承的结构

运行下面这段程序:

#include<iostream>
using namespace std;
typedef void(*PFUN)();
class B
{
public:
     B() :_b(0){}
     virtual void fun1()
     {
          cout << "B::fun1()" << endl;
     }
     virtual void fun2()
     {
          cout << "B::fun2()" << endl;
     }    
private:
     int _b;
};
class D:public B
{
public:
     D() :_d(1){}
     void fun1()
     {
          cout << "D::fun1()" << endl;
     }
     virtual void fun3()
     {
          cout << "D::fun3()" << endl;
     }
private:
     int _d;
};
void PrintVT(int b)//根据虚函数表中的函数地址调用虚函数
{
     PFUN pfun = NULL;
     int *ptr = (int *)b;
     int i = 0;
     while (ptr[i])
     {
          pfun = (PFUN)ptr[i];//将虚函数的地址转换为函数指针
          pfun();//用函数指针调用函数
          i++;
     }
}
int main()
{
     D d;
     PrintVT(*(int *)&d);//取出虚函数表的地址
     getchar();
     return 0;
}

我们在内存窗口可以看到:

上面程序的功能是调用虚函数表中函数的地址所对应的函数,程序运行结果如下:

现在我们可以知道单一继承的内存布局了

                                                                     单一继承对象模型

单一继承的内存布局是:

1)对象的最前面放的是虚函数表的地址,然后根据继承的顺序依次放置成员变量的地址。

2)虚表里按继承顺序先放置派生类从基类继承来的虚函数的地址,然后是派生类自己的虚函数的地址。

3)满足覆盖条件的派生类的虚函数地址覆盖了基类虚函数的地址。

覆盖:

1)不同作用域(基类和派生类中)

2)函数名相同,参数列表相同,返回值类型相同(协变除外)

3)为虚函数(virtual)

注:协变是指基类虚函数返回值为基类类型的指针,派生类虚函数的返回值为派生类类型的指针

多重继承

未完待续。。。

时间: 2024-10-08 18:03:46

探索c++虚函数表的相关文章

探索虚函数表

探索虚函数表 虚函数表是通过一块连续内存来存储类虚函数的地址.这张表解决了继承.虚函数(重写)的问题.向一个派生类对象实例时,虚函数表在有虚函数的对象实例中都存在一张虚函数表,当使用基类指针/引用来指就像一张地图,指明了实际应该调用的函数. class Base { public : virtual void func1() {} virtual void func2() {} private : int a ; }; void Test1 () { Base b1; }

C++中的虚函数表是什么时期建立的?(阿里内推面试题)

虚函数表是在什么时期建立的? 最近参加阿里巴巴公司的内推,面试官问了“虚函数表是在什么时期建立的?”.因为以前对虚函数表的理解不够多,所以就根据程序构建(Build)的四个过程(预编译.编译.汇编和链接),推导出虚函数表应该是在编译器确定的,原因如下: 1)预编译器主要处理那些源代码文件中的以“#”开始的预编译指令,如“#include”.“#define”.很明显这个过程可以排除. 2)汇编器是将编译器生成的汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令.汇编过程相对于

C++虚函数及虚函数表解析

一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Function):基类中没有实现体的虚函数称为纯虚函数(有纯虚函数的基类称为虚基类).C++  “虚函数”的存在是为了实现面向对象中的“多态”,即父类类别的指针(或者引用)指向其子类的实例,然后通过父类的指针(或者引用)调用实际子类的成员函数.通过动态赋值,实现调用不同的子类的成员函数(动态绑定).正是因为这种

C++虚函数表浅析

以前看到虚函数觉得很神奇,为什么就能实现多态了呢.我自己曾设想,要实现运行时多态,应该让对象的某个部分始终指向一个固定的地址,子类继承的时候,就修改这个地址的内容.这样,父类和子类都是到同一个固定地址去读取内容,在运行时就能表现不同行为. 在看了<深度探索c++对象模型>之后,发现思路是类似的.在对象中,有一个指针指向一张虚函数表,里面按照次序存放了每一个虚函数,当子类继承的时候,即到虚函数表的指定位置去修改函数地址.当我们通过父类指针来操作一个子类的时候,调用虚函数,都是通过虚函数表+固定的

虚函数表存放在哪里

from: here 1.虚函数表是全局共享的元素,即全局仅有一个. 2.虚函数表类似一个数组,类对象中存储vptr指针,指向虚函数表.即虚函数表不是函数,不是程序代码,不肯能存储在代码段. 3.虚函数表存储虚函数的地址,即虚函数表的元素是指向类成员函数的指针,而类中虚函数的个数在编译时期可以确定,即虚函数表的大小可以确定,即大小是在编译时期确定的,不必动态分配内存空间存储虚函数表,所以不再堆中. 根据以上特征,虚函数表类似于类中静态成员变量.静态成员变量也是全局共享,大小确定. 所以我推测虚函

关于C++中虚函数表存放位置的思考

其实这是我前一段时间思考过的一个问题,是在看<深入探索C++对象模型>这本书的时候我产生的一个疑问,最近在网上又看到类似的帖子,贴出来看看: 我看到了很多有意思的答案,都回答的比较好,下面贴出一些具有代表性的: Answer 1: Answer 2: 我们都知道,虚函数是多态机制的基础,就是在程序在运行期根据调用的对象来判断具体调用哪个函数,现在我们来说说它的具体实现原理,主要说一下我自己的理解,如果有什么不对的地方请指正在每个包含有虚函数的类的对象的最前面(是指这个对象对象内存布局的最前面,

从逆向的角度去理解C++虚函数表

很久没有写过文章了,自己一直是做C/C++开发的,我一直认为,作为一个C/C++程序员,如果能够好好学一下汇编和逆向分析,那么对于我们去理解C/C++将会有很大的帮助,因为程序中所有的奥秘都藏在汇编中,很多问题我们从表面上无法看出到底是为什么,只要用逆向工具一分析,很快就能知道其中的所以然来.我们都知道虚函数表是放在类对象的最前面,但是很多人并不知道虚函数表的第一项存放的是什么,下面我用IDA分析一下C++的虚函数调用,从汇编的角度去理解虚函数.此文只适合具有逆向分析基础的读者,如果没有逆向分析

单继承与多继承中的虚函数表和虚函数指针

首先,我们了解一下何为单继承,何为多继承?? 单继承:一个子类只有一个直接父类. 多继承:一个子类有两个或多个直接父类. 单继承中的虚函数表分析: 示例程序: #include <iostream> using namespace std; typedef void(*FUNC)(); class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virt

C++ 虚函数表解析

转自陈浩的博客 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的书籍.在这篇文章中,我只想从虚函数的实现