美文网首页
c++虚函数与虚表初步

c++虚函数与虚表初步

作者: FakeCSer爱去网吧 | 来源:发表于2020-04-24 18:13 被阅读0次

虚指针与虚表

  • 虚表和虚函数是为了实现动态多态的机制,由编译器实现

  • 当一个类本身定义了虚函数,或其父类有虚函数时,编译器为该创建一个虚函数表,表中按函数定义的顺序存放指向虚函数的指针。

  • 带虚函数的类实例化为对象的时候,在堆栈上给对象的开始位置加一个虚函数指针,(放在开始是为了保证在多层继承或多重继承的情况下能以最高)

  • 函数表vtable在Linux/Unix中存放在可执行文件的只读数据段中(rodata),这与微软的编译器将虚函数表存放在常量段存在一些差别

  • 虚函数表是class specific的,也就是针对一个类来说的,这里有点像一个类里面的staic成员变量,即它是属于一个类所有对象的,不是属于某一个对象特有的,是一个类所有对象共有的。

代码:通过函数指针访问类对象中的虚函数表,来调用虚表中的虚函数
  • 对象的地址就是存放虚指针的地址,long * vptrAddress = (long *)(&a);
  • 虚指针指向虚表,long* vfunAddress = (long*)*vptrAddress;
  • 虚表中存放虚函数的地址,用函数指针取函数,vfunc = (F)*(long*)vfunAddress;
#include <iostream>
using namespace std;
class A
{
public:
    virtual void Fun(){cout<<"this is A::Fun()"<<endl;}
    virtual void Fun1(){cout<<"this is A::Fun1()"<<endl;}
};

typedef void (*F)();
F vfunc;//定义和声明函数指针

int main()
{
    A a;
//获取对象首地址(即虚表指针)
    long * vptrAddress = (long *)(&a);
    cout << vptrAddress<<endl;
//获取虚表的首地址
    long* vfunAddress = (long*)*vptrAddress;
    cout << vfunAddress<<endl;

//用函数指针直接调用地址的方法调用类中的函数
//  vfunc = (F)*((long*)*(long*)(&a));
    vfunc = (F)*(long*)vfunAddress; 
    vfunc();
//指针指向虚表下一个函数的地址,赋给函数指针来进行调用
    vfunc = (F)*((long*)vfunAddress+1);
    vfunc();
    return 0;
}

注意地址要用long *来存,不然存不下,指向不知道什么地方造成段错误
因为64位机器上,指针是8字节的(64/8),所以用long,在32位机器上,地址是4字节
运行结果:



又学到一个牛逼的方法
long** pVtab= (long**)&a;来操作
此时pVtab[0]就是虚函数表地址,pVtab[1]依次往下就是成员变量,注意内存对齐,如果成员有连续两个int,取到的就是一个不想要的值

#include <iostream>
using namespace std;
class A
{
public:
    virtual void Fun(){cout<<"this is A::Fun()"<<endl;}
    virtual void Fun1(){cout<<"this is A::Fun1()"<<endl;}
    A(int MEM,int MEM1)
        :mem(MEM),mem1(MEM1){}  
public:
    int mem;
    long mem1;
};

typedef void (*F)(void);
F vfunc;//定义和声明函数指针
A a(10,20);

long** pVtab = (long**)&a;

int main()
{
    vfunc = (F)pVtab[0][0];
    vfunc();
    
    vfunc = (F)pVtab[0][1];
    vfunc();
//access mem
    cout << "mem="<<(long)pVtab[1]<<endl;
    cout << "mem1="<<(long)pVtab[2]<<endl;
    
    return 0;
}

今天学习this指针的时候又在原程序上加了些功能

#include <iostream>
using namespace std;
class A
{
    public:
        virtual void Fun(){cout<<"this is A::Fun()"<<endl;}
        virtual void Fun1(){cout<<"this is A::Fun1()"<<endl;}
        A(int MEM,int MEM1)
            :mem(MEM),mem1(MEM1){}  
        void showThis(){cout<<"this pointer: " << "\t"<< hex << this << endl;}
    public:
        int mem;
        long mem1;
};

typedef void (*F)(void);
F vfunc;//定义和声明函数指针
A a(10,20);

long** pVtab = (long**)&a;

int main()
{
    //access function member
    vfunc = (F)pVtab[0][0];
    vfunc();

    vfunc = (F)pVtab[0][1];
    vfunc();
    //access data member
    cout << "mem="<< (long)pVtab[1] << endl;
    cout << "mem1="<< (long)pVtab[2] << endl;
    cout << "addr of vp: " << "\t" << hex << &pVtab[0] << endl; 
    cout << "addr of a: " << "\t" << hex << &a << endl;
    a.showThis();
    return 0;
}

可见,this指针指向的地址==对象的首地址(对象的位置)==虚指针的位置

相关文章

  • c++虚函数与虚表初步

    虚指针与虚表 虚表和虚函数是为了实现动态多态的机制,由编译器实现 当一个类本身定义了虚函数,或其父类有虚函数时,编...

  • GeekBand-C++面向对象高级编程(下)-Week2

    对象模型:虚函数表(vtbl)与虚表指针(vptr) 我们知道,C++中,可以通过虚函数来实现多态性,而虚函数是通...

  • C++ 虚函数表、虚函数讲解

    前言 近期有不少同学私信我询问关于C++ 虚表和虚函数的相关问题,于是就打算写一篇关于C++虚函数和虚表的原理文章...

  • 第二周(Geek Band)

    对象模型 1、vptr和vtbl(虚函数与虚表) 调用虚函数vfun,通过虚指针vptr找到虚表vtbl,通过虚表...

  • pwnable.kr之uaf && c++虚函数

    c++的逆向还是要熟悉下。 一、关于c++虚函数 虚函数使得c++能够实现多态,每个类有一个虚表,每个对象在实现的...

  • C++虚函数表

    虚函数表 C++中虚函数是通过一张虚函数表(Virtual Table)来实现的,在这个表中,主要是一个类的虚函数...

  • C++虚函数初步

    刚开始接触C++中的虚函数,云里雾里的感觉,后面看了几篇博客,了解了一些。 C++中面向对象程序设计中具有多态性,...

  • Swift5.1学习随笔之多态

    多态的实现原理: OC:Runtime C++:虚表(虚函数表) Swift:纯Swift没有Runtime,更加...

  • c++ vtable 解析上篇 | 编程知识3

    从汇编指令的角度来看 c++ 虚表的虚函数的调用方式,看虚表​应该如何设计。 1、环境 x86_64-apple-...

  • C++ 虚函数

    C++ 虚函数 虚函数 基类中使用virtual关键字声明的函数,称为虚函数。虚函数的实现,通过虚函数表来实现的。...

网友评论

      本文标题:c++虚函数与虚表初步

      本文链接:https://www.haomeiwen.com/subject/xqsxwhtx.html