虚函数表指针vptr的测试

  类的虚函数调用是通过虚函数表实现的。所谓虚函数表,是编译器自动为一个带有虚函数的类生成的一块内存空间,其中存储着每一个虚函数的入口地址。由于函数的入口地址可以看成一个指针类型,因此这些虚函数的地址间隔为四个字节。而每一个带有虚函数类的实例,编译器都会为其生成一个虚函数指针——vptr,在类的对象初始化完毕后,它将指向虚函数表。

  这个vptr指针将位于类对象的首部,即作为第一个成员变量,处于类对象代表的内存块的前四个字节中。为了便于理解和复习,在此将其内存结构以图示之。

  查阅资料得知,C++标准并没有规定虚函数的实现方法,使用虚函数表的方法是编译器厂商制定的,因此有必要对其进行一个代码验证,测试一下vptr指针。

  测试的目标是:得到类对象的vptr指针,然后通过vptr指针得到虚函数的入口地址,间接的调用虚函数。

  代码如下:

class Test
{
public:
    Test() : a(0) {}

    virtual void print1() { cout << "Test print1" << endl; }

    virtual void print2() { cout << "Test print2" << endl; }

private:
    int a;
};

//测试vptr指针
//vptr指向了虚函数表,虚函数表里存放着类的所有虚函数的入口地址
int main()
{
    Test t;

    //得到vptr的值

    //由于vptr指向的就是函数指针,因此其步长应该是4,所以可以用int*定义
    int *vptr = NULL;

    //vptr是虚函数类的第一个成员变量
    memcpy(&vptr, &t, 4);
    printf("vprt=%d\n", vptr);

    typedef void (*pFunc)();

    //通过vptr得到虚函数的入口地址,然后转化成函数指针
    pFunc p1 = (pFunc)*vptr; //vptr指向了虚函数表,也即第一个虚函数的入口地址
    p1();

    pFunc p2 = (pFunc)*(vptr + 1); //指向第二个虚函数
    p2();

    return 0;
}

  如此,p1应是成员函数print1,p2应是成员函数print2。实际运行结果也无误。证明了vptr和vbtl的存在和存在方式。

时间: 2024-10-09 16:17:31

虚函数表指针vptr的测试的相关文章

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++学习 - 虚表,虚函数,虚函数表指针学习笔记

虚函数 虚函数就是用virtual来修饰的函数.虚函数是实现C++多态的基础. 虚表 每个类都会为自己类的虚函数创建一个表,来存放类内部的虚函数成员. 虚函数表指针 每个类在构造函数里面进行虚表和虚表指针的初始化. 下面看一段代码: // // main.cpp // VirtualTable // // Created by Alps on 15/4/14. // Copyright (c) 2015年 chen. All rights reserved. // #include <iostr

C++虚函数表指针的值

前段时间在软件编写过程中碰到一个问题,顺便将感想写一下,虽然不知道是否随编译器的实现而异,但约束一下自己写代码的习惯总没错. 基类虚函数表指针值的变化 若基类中含有虚函数,当创建派生类对象时,虚函数表指针的值在进入派生类构造函数的函数体时会被修改为指向派生类新创建的虚函数表.当基类析构函数被调用时,虚函数表指针的值会被修改为指向基类创建的虚函数表,这样做是为了防止在基类析构函数中访问可能被释放了的派生类的那部分内存(尤其重要).一旦派生对象调用了基类析构函数,则所有指向该派生对象的基类指针都会失

虚函数表指针个数

转自 https://blog.csdn.net/xiaxzhou/article/details/76576516 讲的很透彻,对于理解虚指针 类的成员函数: 总结:普通继承:子类不会出现新的虚函数表,而是把自己的虚函数放到父亲的虚函数表上 虚继承    :子类会出现一个vbptr     子类出现一个新的虚函数表,用来放自己的虚函数,父类的虚函数表指针也会继承下来 类的数据成员: 总结:普通继承:很简单... 虚继承    :考虑好菱形继承 大小方面的问题,纯粹按照内存对齐等考虑 原文地址:

虚函数表指针位置

一般VC和BCB是将vPtr放在类实例的前四个字节,GCC是放在末尾.在某些情况下需要考虑表指针的位置,比如序列化的时候. 其实只需将类实例的首地址与类的第一个成员变量地址相比较就可得知虚表指针的位置. class A { A(void){} virtual void Foo(void){} }; int main() { A a; char *p1 = reinterpret_cast<char*>(&a); char *p2 = reinterpret_cast<char*&

深入剖析C++多态、VPTR指针、虚函数表

在讲多态之前,我们先来说说关于多态的一个基石------类型兼容性原则. 一.背景知识 1.类型兼容性原则 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员.这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决.类型兼容规则中所指的替代包括以下情况: 子类对象可以当作父类对象使用 子类对象可以直接赋值给父类对象 子类对象可以直接初始化父类对象 父类指针可以直接指向子类对

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

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

C++之虚函数表

本文引自:http://songlee24.github.io/blog/2014/09/02/c-plus-plus-jin-jie-zhi-xu-han-shu-biao/ C++通过继承(inheritance)和虚函数(virtual function)来实现多态性.所谓多态,简单地说就是,将基类的指针或引用绑定到子类的实例,然后通过基类的指针或引用调用实际子类的成员函数(虚函数).本文将介绍单继承.多重继承下虚函数的实现机制. 一.虚函数表 为了支持虚函数机制,编译器为每一个拥有虚函数

C++类成员空间分配和虚函数表

最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cout<<"Base display()"<<endl; } void say(){ cout<<"Base say()"<<endl; } public: virtual void func(){cout <<