C++知识点随笔(五):虚继承

原创 2015年08月20日 20:33:30

虚继承的出现就是为了解决多继承中访问不明确的问题。
首先让我们先看一下虚继承的代码:

#include<iostream>
using namespace std;

class AA
{
public:
    int m_a;
    AA()
    {
        m_a = 100;
    }
};

class BB : virtual public AA
{
public:
    int m_b;
    BB()
    {
        m_a = 200;
    }
};

class CC : virtual public AA
{
public:
    int m_c;
    CC()
    {
        m_a = 300;
    }
};

class DD : public BB, public CC
{
public:
    int m_d;
    DD()
    {
        m_a = 400;
    }
};

int main()
{
    DD dd;
    cout << sizeof(dd) << endl;
    cout << &dd << endl;
    cout << &dd.m_a << endl;
    cout << &dd.m_b << endl;
    cout << &dd.m_c << endl;
    cout << &dd.m_d << endl;

    cout << dd.AA::m_a << endl;
    cout << dd.BB::m_a << endl;
    cout << dd.CC::m_a << endl;
    cout << dd.m_a << endl;

    system("pause");
    return 0;
}

输出结果:
这里写图片描述
dd对象在内存中的结构如下:
这里写图片描述
我们看到虚继承中,内存的分配是与多继承不同的,我们不再是赋值两份AA对象,而是将虚基类放在了最后面,然后原来的BB和CC所继承的AA的地址存放的是指向AA对象的指针,这样做的另一个好处是还可以节约内存空间,因为如果AA对象的大小是100个字节,那我们也只需要一个4字节的指针指向它就可以了,而不用赋值一份儿占用空间。

注意:虚基类只有一份,并且所有继承虚基类的子类都要虚继承,否则如果有一个不是虚继承的那也会再复制一份AA,内存中同样存在了两份AA,那么访问不明确的问题就还是存在。

虚基类为什么要放在最后?
因为我们在使用这个虚基类的时候首先要知道是哪一个对象(就是指向虚基类的指针)调用的它,我们把虚基类放在最后就是要保证:前面的所有的对象使用虚基类的时候都是通过指向虚基类的指针找到的。如果我们不放在后面而是放在前面,那么找到虚基类就有了两种方式:直接使用对象的地址 or 指向虚基类的指针,这样我们在使用虚基类的时候还要加一个判断,来判断到底是谁调用的呢?这样显然更麻烦了。所以我们要把虚基类放在后面,让所有子类都是通过指向虚基类的指针来找到它。

含有虚函数的虚继承

我们首先看一道题:下列程序的结果是什么?

#include <iostream>
#include <memory.h>
#include <assert.h>
using namespace std;

class A
{
    char k[3];
public:
    virtual void aa(){};
};

class B : public virtual A
{
    char j[3];
public:
    virtual void bb(){};
};

class C : public virtual B
{
    char i[3];
public:
    virtual void cc(){};
};

int main(int arge,char *argv[])
{
    cout<<"sizeof(A):"<<sizeof(A)<<endl;
    cout<<"sizeof(B):"<<sizeof(B)<<endl;
    cout<<"sizeof(C):"<<sizeof(C)<<endl;

    system("pause");
    return 0;
}

输出结果:
这里写图片描述
我们来看一下c对象在内存中的结构:
这里写图片描述
从图中我们可以看出:每个类最初始的4个字节都是指向虚函数列表的指针,由于A是虚基类,没有父类,所以A只有8个字节大小;而B虚继承了A,所以B要有一个指向A类地址的指针,所以B类是12+8(A的大小)=20;同样,C类虚继承了B,所以C要有一个指向B类地址的指针,所以C类是12+20(B的大小)=32。

什么情况下会产生新的虚函数列表呢?
为了便于理解,我们首先来看一下上一个例子中,改为普通继承情况下的输出:
这里写图片描述
我们现在再看一下c对象在内存中的结构:
这里写图片描述
那么我们是通过什么方式来确定他们的结构的呢?就是分别用不同类型的指针去指向c这个对象。如下:

C c;
A* a = &c;
B* b = &c;

当我们使用普通继承的时候a、b、c所返回的地址都是相同的,即 0C 地址。所以在实现多态的时候,父类将虚函数加到了这个虚表中,而他的子类在重写虚函数的时候也是首先复制了父类的虚函数列表,然后用自己重写的虚函数的指针覆盖父类所存入的指针。这样我们在父类调用多态的时候就可以直接从虚表里找到新的虚函数的地址了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++中虚继承的作用及底层实现原理

虚继承和虚函数是完全无相关的两个概念。 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:其一,浪费存储空间;第二,存在二义性问题,通常可...
  • bxw1992
  • bxw1992
  • 2017年08月30日 22:26
  • 1427

C++之虚函数(三)虚继承和虚基类详解

多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名...
  • Bruce_0712
  • Bruce_0712
  • 2017年02月18日 10:52
  • 388

C++虚继承与普通继承的区别

虚继承的时候在子类的对象中会多出一个叫虚类指针的大小,有的资料说这个指针指向的内存里面包含了该子类的偏移量和到基类的距离。但是我跟踪过这段内存,发现里面的数据没有规律,也找不到更多的支撑材料,权且先知...
  • bama2488313716
  • bama2488313716
  • 2015年04月16日 15:54
  • 427

c++学习之继承篇(多重继承之虚继承)

虚继承 是面向对象编程中的一种技术,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。形式:在继承定义中包含了virtual关键字的继承关系,如下图中,...
  • hudfang
  • hudfang
  • 2016年01月25日 12:09
  • 909

C++ - 虚继承(virtual inheritance) 详解

虚继承(virtual inheritance) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/23739633 在...
  • u012515223
  • u012515223
  • 2014年04月15日 10:09
  • 3053

C++ 虚继承和虚函数同时存在的对象模型

如果说没有虚函数的虚继承只是一个噩梦的话,那么这里就是真正的炼狱。这个C++中最复杂的继承层次在VC上的实现其实我没有完全理解,摸爬滚打了一番也算得出了微软的实现方法吧,至于一些刁钻的实现方式我也想不...
  • chengonghao
  • chengonghao
  • 2016年06月22日 20:16
  • 1549

C++虚继承的内存结构

我用vc2003观测到的实际情况是。在类中增加一个指针(VBPTR)指向一个VBTBL,这个VBTBL的第一项记载的是从VBPTR 与本类的偏移地址,如果本类有虚函数,那么第一项是FF FF FF F...
  • fengguowuhengwin
  • fengguowuhengwin
  • 2013年11月04日 20:50
  • 608

【C++拾遗】 从内存布局看C++虚继承的实现原理

准备工作 1、VS2012使用命令行选项查看对象的内存布局 微软的Visual Studio提供给用户显示C++对象在内存中的布局的选项:/d1reportSingleClassLayout。使用...
  • Xiejingfa
  • Xiejingfa
  • 2015年08月27日 16:49
  • 2720

C++虚继承的意义和使用

虚继承:多个派生类保存相同基类的同名成员时,虽可以在不同的数据成员中分别存放不同的数据 ,但我们只需要相同的一份。 解决了多父类重复成员只保留一份的问题。 比如现在有一个沙发床,它既有床的...
  • blank__box
  • blank__box
  • 2017年10月15日 11:05
  • 158

【c++】深度探索虚继承内存布局

C++中虚拟继承的概念 为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同...
  • Always__
  • Always__
  • 2016年04月22日 17:11
  • 715
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++知识点随笔(五):虚继承
举报原因:
原因补充:

(最多只允许输入30个字)