设为首页 加入收藏

TOP

C++虚函数表实例分析
2019-01-03 20:09:09 】 浏览:105
Tags:函数 实例分析

我们先来看看代码:


#include <iostream>


using namespace std;


class Base {
public:
    virtual void f() {cout<<"base::f"<<endl;}
    virtual void g() {cout<<"base::g"<<endl;}
    virtual void h() {cout<<"base::h"<<endl;}
};


class Derive : public Base{
public:
    void g() {cout<<"derive::g"<<endl;}
};


//可以稍后再看
int main () {
    cout<<"size of Base: "<<sizeof(Base)<<endl;


    typedef void(*Func)(void);
    Base b;
    Base *d = new Derive();


    long* pvptr = (long*)d;
    long* vptr = (long*)*pvptr;
    Func f = (Func)vptr[0];
    Func g = (Func)vptr[1];
    Func h = (Func)vptr[2];


    f();
    g();
    h();


    return 0;
}


C++虚函数表实例分析


都知道C++中的多态是用虚函数实现的: 子类覆盖父类的虚函数, 然后声明一个指向子类对象的父类指针, 如Base *b = new Derive();


当调用b->f()时, 调用的是子类的Derive::f()。


这种机制内部由虚函数表实现,下面对虚函数表结构进行分析,并且用GDB验证。


1. 基础知识:


(1) 32位os 指针长度为4字节, 64位os 指针长度为8字节, 下面的分析环境为64位 linux & g++ 4.8.4.


(2) new一个对象时, 只为类中成员变量分配空间, 对象之间共享成员函数。


2. _vptr


    运行下上面的代码发现sizeof(Base) = 8, 说明编译器在类中自动添加了一个8字节的成员变量, 这个变量就是_vptr, 指向虚函数表的指针。


_vptr有些文章里说gcc是把它放在对象内存的末尾,VC是放在开始, 我编译是用的g++,验证了下是放在开始的:


验证代码:取对象a的地址与a第一个成员变量n的地址比较,如果不等,说明对象地址开始放的是_vptr. 也可以用gdb直接print a 会发现_vptr在开始


class A
{
public:
      int n;
      virtual void Foo(void){}
};


int main()
{
    A a;
    char *p1 = reinterpret_cast<char*>(&a);
    char *p2 = reinterpret_cast<char*>(&a.n);
    if(p1 == p2)
    {
        cout<<"vPtr is in the end of class instance!"<<endl;
    }else
    {
        cout<<"vPtr is in the head of class instance!"<<endl;
    }
    return 1;
}


(3) 虚函数表
    包含虚函数的类才会有虚函数表, 同属于一个类的对象共享虚函数表, 但是有各自的_vptr.
    虚函数表实质是一个指针数组,里面存的是虚函数的函数指针。


Base中虚函数表结构:



Derive中虚函数表结构:



(4)验证
运行上面代码结果:
    size of Base: 8
    base::f
    derive::g
    base::h


说明Derive的虚函数表结构跟上面分析的是一致的:
    d对象的首地址就是vptr指针的地址-pvptr,
    取pvptr的值就是vptr-虚函数表的地址
    取vptr中[0][1][2]的值就是这三个函数的地址
    通过函数地址就直接可以运行三个虚函数了。
    函数表中Base::g()函数指针被Derive中的Derive::g()函数指针覆盖, 所以执行的时候是调用的Derive::g()


(5)多继承



 




】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Ubunutu下使用g++ 编译错误之没有.. 下一篇C++虚函数在g++中的实现分析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目