c++对象模型05:虚继承内存布局

本文详细解析了虚继承的工作原理,包括派生类内存结构的变化、虚函数表与虚基类指针的作用,以及菱形继承下D类对象模型的构成。通过C++代码演示,展示了虚继承如何解决多重继承中的问题和多态实现方式。

虚继承

虚继承解决了菱形继承中最派生类拥有多个间接父类实例的情况。虚继承的派生类的内存布局与普通继承很多不同,主要体现在:

  • 虚继承的派生类,如果定义了新的虚函数,则编译器为其生成一个虚函数指针(vptr)以及一张虚函数表。该vptr位于对象内存最前面。(非虚继承时,派生类新的虚函数直接扩展在基类虚函数表的下面。)
  • 虚继承的派生类有单独的虚函数表,基类也有单独的虚函数表,两部分之间用一个四个字节的0x00000000来作为分界。
  • 虚继承的派生类对象中,含有四字节的虚基表指针。

在C++对象模型中,虚继承而来的派生类会生成一个隐藏的虚基类指针(vbptr),在Microsoft Visual C++中,虚基类表指针总是在虚函数表指针之后,因而,对某个类实例来说,如果它有虚基类指针,那么虚基类指针可能在实例的0字节偏移处(该类没有vptr时,vbptr就处于类实例内存布局的最前面,否则vptr处于类实例内存布局的最前面),也可能在类实例的4字节偏移处。
一个类的虚基类指针指向的虚基类表,与虚函数表一样,虚基类表也由多个条目组成,条目中存放的是偏移值。第一个条目存放虚基类表指针(vbptr)所在地址到该类内存首地址的偏移值,由上面的分析我们知道,这个偏移值为0(类没有vptr)或者-4(类有虚函数,此时有vptr)。虚基类表的第二、第三…个条目依次为该类的最左虚继承父类、次左虚继承父类…的内存地址相对于虚基类表指针的偏移值。我们通过一张图来更好地理解。

在这里插入图片描述

代码

class B

{
   
   

public:

    int ib;

public:

    B(int i = 1) :ib(i) {
   
   }

    virtual void f() {
   
    cout << "B::f()" ; }

    virtual void Bf() {
   
    cout << "B::Bf()" ; }

};

class B1 : virtual public B

{
   
   

public:

    int ib1;

public:

    B1(int i = 100) :ib1(i) {
   
   }

    virtual void f() {
   
    cout << "B1::f()" ; }

    virtual void f1() {
   
    cout << "B1::f1()" ; }

    virtual void Bf1() {
   
    cout << "B1::Bf1()" ; }



};

对象模型

代码演示

typedef void(*Fun)(void);
int main()
{
   
   
    B1 a;
    cout << "B1对象内存大小为:" << sizeof(a) << endl;

    //取得B1的虚函数表
    cout << "[0]B1::vptr";
    cout << "\t地址:" << (int*)(&a) << endl;

    //输出虚表B1::vptr中的函数
    for (int i = 0; i < 2; ++i)
    {
   
   
        cout << "  [" << i << "]";
        Fun fun1 = (Fun) * ((int*)*(int*)(&a) + i);
        fun1();
        cout << "\t地址:\t" << *((int*)*(int*)(&a) + i) << endl;
    }

    //[1]
    cout << "[1]vbptr ";
    cout << "\t地址:" << (int*)(&a) + 1 << endl;  //虚表指针的地址
    //输出虚基类指针条目所指的内容
    for (int i = 0; i < 2; i++)
    {
   
   
        cout << "  [" << i << "]";

        cout << *(int*)
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值