c++对象模型之虚函数

1.虚函数表指针位置

  • 一个类有虚函数,则这个类就会有一个虚函数表
  • 该类对象里会有一个虚函数表指针,指向虚函数表的起始地址

位置:虚函数表指针的位置取决于编译器,可能在对象内存开头,也可能在末尾,需要经过测试。

测试代码:

#include <iostream>
class A

{
public:
    int i;
    virtual void testfunc() {}
};

int main()
{
    A a;
    int ilen = sizeof(a);
    char* p1 = reinterpret_cast<char*>(&a);
    char* p2 = reinterpret_cast<char*>(&(a.i));
    if (p1 = p2)
    {
        std::cout << "虚函数表指针在对象内存末尾";
    }
    else
    {
        std::cout << "虚函数表指针在对象内存开头";
    }
 
}

2.手动调用虚函数

class Base
{
public:
    virtual void a() { std::cout << "BASE::a()"; }
    virtual void b() { std::cout << "BASE::b()"; }
    virtual void c() { std::cout << "BASE::c()"; }
};
class Derive : public Base
{
public:
    virtual void a() { std::cout << "Derive::a()"; }

};
int main()
{
    Derive* pd = new Derive(); // 派生类指针
    int* ptr = (int*)pd; //指向对象pd的指针转换为int*,pd对象里只有虚函数表指针
    unsigned int * vptr = (unsigned int*)(*ptr); //(*ptr)表示指向的对象,也就是pd对象,内存里的值就是虚函数表的地址。
    for (int i = 0; i <= 2; i++)
    {
        printf("vptr[%d] = 0x: %p\n", i, &vptr[i]);
    }

 
}

3.虚函数表分析

  1. 包含虚函数的类才有虚函数表,同属于一个类的 对象共享这个虚函数表。
  2. 父类中有虚函数等于子类有虚函数。父类中有虚函数表,则子类肯定也有虚函数表,即使不覆盖父类的任何虚函数。
  3. 如果子类中完全没有新的虚函数,则父类和子类的虚函数表内容一致,仅仅是内容一致。两个虚函数表位于不同的内存地址

4.子类复制给父类,虚函数表指针处理

Base base = derive;

按道理,base对象的数据是从derive复制过来,即两个虚函数表指针应该一致,但实际不一致。

编译器所做的处理:1.生成一个base对象 2.用derive初始化base对象的值,初始化时,

5.多重继承下的虚函数表

  1. 一个对象,如果它所属的类有多个基类,则有多个虚函数表指针
  2. 多重继承下,对应各个基类的虚函数表指针按继承顺序放置在类的内存空间中,且子类与第一个基类共用一个vptr虚函数表指针

6.虚函数表创建时机

虚函数表指针创建时机

vptr是跟着对象走的,对象创建出来,才存在这个vptr。

  1. 编译时候,编译器会往类的构造函数中安插为vptr赋值的语句
  2. 运行时候,创建对象时,执行构造函数,因为有为vptr赋值的语句,所以vptr变得有效

虚函数表创建时机

  1. 编译时候,编译器已经为每个类确定好了对应的虚函数表的内容

 

7.静态联编和动态联编

静态联编:编译时候就能确定调用哪个函数,把调用语句和被调用函数绑定到一起,通过call调用函数

动态联编:运行时候,根据实际情况,动态把调用函数和被调用函数绑定到一起,动态联编一般只有在多态和虚函数情况下才存在

直接定义对象:

通过对象调用虚函数,根本用不到虚函数表,即便是把虚函数表指针清零,也不影响调用,因为是通过静态联编在编译时候确定了函数调用,通过call调用

定义指针:

通过指针调用虚函数,并不是直接调用,而是通过虚函数表指针找到虚函数表,然后找到虚函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值