虚继承

多继承和多重继承导致的问题?

多继承:就是某一个类继承了好几个基类
多重继承:就是类被一层一层的继承

这里写图片描述

在上面的这幅图中,类B会拷贝一份A的数据,类C会拷贝一份A的数据,那么这时候类D再继承B和C的话,就会在类D中存在两份A的拷贝 。这是绝对不允许的 。一是浪费空间,二是存在二义性

举例如下:

这里写图片描述

农民工中就会存在两份人的数据 。

虚继承的出现和实现原理 ?

正因为上面所说的问题的出现,为了解决这个问题,提出了虚继承的概念 。 那么它是如何实现的呐?

  1. 虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。

  2. 实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。

  3. 在这里我们可以对比虚函数的实现原理:他们有相似之处,都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)。

    • 虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。

    • 虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。

参考博文:

此篇博客有关于虚继承详细的内存分布情况
http://blog.csdn.net/xiejingfa/article/details/48028491

实例讲解实现原理

我以上面的例子来解释一下虚继承的实现原理,其中工人和农民会以虚继承的方式继承人 。

(1)在工人和农民中各自都会有一个虚基类指针与虚基类表
这里写图片描述
(2)那么他们是如何找到基类中的成员的呐?就是下面这样子的
这里写图片描述
(3)再来就是农民工以 public 方式继承工人和农民
这里写图片描述
可见,在这次的继承中并没有将虚基类表继承下来!其实想一下也很简单了,只要有指针指向就行了呗!

(4)补充说明的是:虚基类表存储的是,虚基类相对直接继承类的偏移(农民工并非是虚基类的直接继承类,工人和农民才是)

代码举例:

<1> 不用虚继承时:

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Person{
    public:
    Person(string theColor){
        m_strColor = theColor ;
        cout << "Person()  " << endl ;
    }
    virtual ~Person(){
        cout << "~Person "<< endl ;
    }
    void printColor(){
        cout << m_strColor << endl ;
        cout <<"Person ------ printColor "<< endl ;
    }
    protected:
    string m_strColor ;
};
class Farmer :public   Person  //颜色 blue 
{
    public:
    Farmer(string thename = "jack" ,string color = "blue"):Person("Farmer"+color) 
    {
        m_strName = thename ;
        cout << "Farmer()" << endl ;
    }
    virtual ~Farmer(){
        cout << "~Farmer() " << endl ;
    }
    protected:
    string m_strName ;
};
class Worker :  public  Person  // 颜色 red  
{
    public:
    Worker(string thecode  = "001" ,string color = "red "):Person("Worker"+color )
    {
        m_strCode = thecode  ;
        cout << "Worker() " << endl ;
    }
    virtual ~Worker(){
        cout << "~Worker " << endl ;
    }
    protected:
    string m_strCode  ;
};
class FarmerWorker : public Farmer ,public Worker 
{
    public:
    FarmerWorker(string thename,
                 string thecode ,
                 string color):Farmer(thename,color),Worker(thecode,color )
    {
        cout << "FarmerWorker()" << endl ;
    }
    ~FarmerWorker(){ 
        cout << "~FarmerWorker()" << endl ;
    }
};
int main(void){
    FarmerWorker  *p = new FarmerWorker("liushegxi","666","yellow ");
    p->Farmer::printColor();
    p->Worker::printColor();
    delete p ;
    p = nullptr ;
    return 0 ;
}

执行结果:
这里写图片描述

可见,它的的确确是有两份”yellow”的!(Person中的数据成员m_strColor 有两份 )

<2> 使用虚继承时:

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Person{
    public:
    Person(string theColor){
        m_strColor = theColor ;
        cout << "Person()  " << endl ;
    }
    virtual ~Person(){
        cout << "~Person "<< endl ;
    }
    void printColor(){
        cout << m_strColor << endl ;
        cout <<"Person ------ printColor "<< endl ;
    }
    protected:
    string m_strColor ;
};
class Farmer : virtual  public   Person  //颜色 blue 
{
    public:
    Farmer(string thename = "jack ",string color = "blue " ):Person(color) 
    {
        m_strName = thename ;
        cout << "Farmer()" << endl ;
    }
    virtual ~Farmer(){
        cout << "~Farmer() " << endl ;
    }
    protected:
    string m_strName ;
};
class Worker :  virtual  public  Person  // 颜色 red  
{
    public:
    Worker(string thecode ="001",string color = "red " ):Person(color )
    {
        m_strCode = thecode  ;
        cout << "Worker() " << endl ;
    }
    virtual ~Worker(){
        cout << "~Worker " << endl ;
    }
    protected:
    string m_strCode  ;
};
class FarmerWorker : public Farmer ,public Worker 
{
    public:
    FarmerWorker(string thename,
                 string thecode ,
                 string the_color):Farmer(thename,the_color),Worker(thecode,the_color),Person(the_color) //注意Person 也得显式的写出来
    {
        cout << "FarmerWorker()" << endl ;
    }
    ~FarmerWorker(){ 
        cout << "~FarmerWorker()" << endl ;
    }
};
int main(void){
    FarmerWorker  *p = new FarmerWorker("liushegxi","666","yellow ");
    p->Farmer::printColor();
    p->Worker::printColor();
    delete p ;
    p = nullptr ;
    return 0 ;
}

执行结果:
这里写图片描述

观察可得,Person 只被实例化了一次,那么它也就只能产生一份数据了,其他类中只有虚基类指针指向它而已。

posted @ 2018-03-14 17:55  Tattoo_Welkin  阅读(423)  评论(0编辑  收藏  举报