c++虚函数表中的内存布局

1.Class的内存分布

#include <iostream>

using namespace std;

#define Debug  cout<<'<'<<__FILE__<<">,"<<__FUNCTION__<<","<<__LINE__<<endl

class Base
{

};

int main()
{
    cout<<sizeof(Base)<<endl;//1

    return 0;
}
#include <iostream>

using namespace std;

#define Debug  cout<<'<'<<__FILE__<<">,"<<__FUNCTION__<<","<<__LINE__<<endl

class Base
{
private:
    int _val;
    int static _staticval;//说明静态成员变量不属于类

public:
    int Getval() const//说明成员函数也不属于类
    {
        return _val;
    }
};

int main()
{
    cout<<sizeof(Base)<<endl;//4

    return 0;
}
#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{
private:
    int _val;
    int static _staticval; // 说明静态成员变量不属于类

public:
    int Getval() const // 说明成员函数也不属于类
    {
        return _val;
    }
};

class Base_A : public Base
{
};

int main()
{
    cout << sizeof(Base_A) << endl; // 4
    printf("%p\n%p\n", &Base::Getval, &Base_A::Getval);
    /*
    00007FF6D2AC1131
    00007FF6D2AC1131   //不重载的话,从派生类继承下来的函数是同一个函数,也就是说"函数的内存不在类里面"
    */

    return 0;
}
#include <iostream>

using namespace std;

#define Debug  cout<<'<'<<__FILE__<<">,"<<__FUNCTION__<<","<<__LINE__<<endl

class Base
{
private:
    int _val;
    int static _staticval;//说明静态成员变量不属于类

public:
    int Getval() const//说明成员函数也不属于类
    {
        return _val;
    }
};

class Base_A : public Base
{
public:
    int Getval() const
    {
        return 0;
    }
};

int main()
{
    cout<<sizeof(Base_A)<<endl;//4
    printf("%p\n%p\n",&Base::Getval,&Base_A::Getval);
    /*
    000000000061fdf0
    000000000061fde0   //重载了所以地址才发生了变化
    */

    return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.其他修改Class中变量的方法

在这里插入图片描述
类这种概念只在编译的时候存在

#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{
private:
    int _val;
    int _valB;
public:
    int GetVal() const
    {
        return _val;
    }
    int GetValB() const
    {
        return _valB;
    }
};



int main()
{
    Base obj;
    int* objPtr = (int*)&obj;
    *objPtr = 999;

    *(objPtr + 1) = 1000;

    cout << obj.GetVal() << endl;//999
    cout << obj.GetValB() << endl;//1000
    

    return 0;
}
#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    Base obj;
    U8* objAddre = (U8*)&obj;//这个类
    U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组

    ((FuncPtr)objArr[0]) ();
    ((FuncPtr)objArr[1]) ();
    ((FuncPtr)objArr[2]) ();

    /*输出
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirB,17
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
    */

    return 0;
}

3.通过虚函数表内存偏移调用虚函数

#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    Base obj;
    U8* objAddre = (U8*)&obj;//这个类
    U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组

    ((FuncPtr)objArr[0]) ();
    ((FuncPtr)objArr[1]) ();
    ((FuncPtr)objArr[2]) ();

    /*输出
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirB,17
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
    */

    return 0;
}
#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    {
        Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();
    }
    {
        Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组

        printf("%p\n",objArr);
    }

    /*输出
    00007FF63F7BBD30
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirB,17
    <D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
    00007FF63F7BBD30///地址一样:说明:同一个类 实例化多个对象 虚函数表指针是一样的
    */

    return 0;
}

在这里插入图片描述

4.继承状态下的虚函数表内存

  • 1.没有重写,虚函数表中的元素地址是一样的
  • 2.重写后,对应的虚函数表中的函数指针就是新的地址
#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

class A_Base : public Base
{
    virtual void VirB()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    {
        A_Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        //printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();
    }
 

    /*输出
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
<D:\vs2022\code\测试cpp语法\main.cpp>,A_Base::VirB,29
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
    */

    return 0;
}

在这里插入图片描述

#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

class A_Base : public Base
{
    virtual void VirB()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    {
        Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        //printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();

        for(int i = 0 ; i < 3 ; i++)
            printf("%p\n", objArr[i]);
    }
    printf(".........................................................\n");
    {
        A_Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        //printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();

        for (int i = 0; i < 3; i++)
            printf("%p\n", objArr[i]);
    }
 

    /*输出
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirB,17
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
00007FF7979B1442
00007FF7979B115E
00007FF7979B1474
.........................................................
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
<D:\vs2022\code\测试cpp语法\main.cpp>,A_Base::VirB,29
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
00007FF7979B1442
00007FF7979B14B0
00007FF7979B1474
    */

    return 0;
}

在这里插入图片描述

5.派生类函数中多出来的虚函数访问(“父类指针指向子类对象”)

“基类指针指向子类对象"或"基类指针指向派生类对象”

#include <iostream>

using namespace std;

#define Debug cout << '<' << __FILE__ << ">," << __FUNCTION__ << "," << __LINE__ << endl

class Base
{

public:
    virtual void VirA()
    {
        Debug;
    }
    virtual void VirB()
    {
        Debug;
    }
    virtual void VirC()
    {
        Debug;
    }
};

class A_Base : public Base
{
    virtual void VirB()
    {
        Debug;
    }

    virtual void VirD()
    {
        Debug;
    }
};

using U8 = long long;
using FuncPtr = void(*)();//函数指针
int main()
{
    {
        Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        //printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();

        for (int i = 0; i < 3; i++)
            printf("%p\n", objArr[i]);
    }
    printf(".........................................................\n");
    {
        A_Base obj;
        U8* objAddre = (U8*)&obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        //printf("%p\n", objArr);
        ((FuncPtr)objArr[0]) ();
        ((FuncPtr)objArr[1]) ();
        ((FuncPtr)objArr[2]) ();

        for (int i = 0; i < 3; i++)
            printf("%p\n", objArr[i]);
    }

    {
        Base* obj = new A_Base;
        //obj->VirD();//报错:常规的方法:基类指针 无法访问 派生类函数中多出来的虚函数
        U8* objAddre = (U8*)obj;//这个类
        U8* objArr = (U8*)(*objAddre);//解引用,这时候,就是那个虚函数的数组
        ((FuncPtr)objArr[3]) ();
    }


    /*输出
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirB,17
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
00007FF71EBE14CE
00007FF71EBE1181
00007FF71EBE150A
.........................................................
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirA,13
<D:\vs2022\code\测试cpp语法\main.cpp>,A_Base::VirB,29
<D:\vs2022\code\测试cpp语法\main.cpp>,Base::VirC,21
00007FF71EBE14CE
00007FF71EBE10A5
00007FF71EBE150A
<D:\vs2022\code\测试cpp语法\main.cpp>,A_Base::VirD,34
    */

    return 0;
}

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏过山河,踏过海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值