天天看点

c++中菱形继承中出现的问题和虚继承虚基类使用普通继承关系的菱形继承如下虚基类虚继承利用虚继承解决,保存多份不同成员变量的问题

目录

  • 普通继承关系的菱形继承如下
  • 虚基类
  • 虚继承
  • 利用虚继承解决,保存多份不同成员变量的问题

普通继承关系的菱形继承如下

c++中菱形继承中出现的问题和虚继承虚基类使用普通继承关系的菱形继承如下虚基类虚继承利用虚继承解决,保存多份不同成员变量的问题

基类Person被public继承以后会生成2份成员变量,再给孙子类的会保存,代码如下,通过代码能看到,孙子类的FarmerWorker的 3个age的内存地址不同,这个不是我们想要的结果.我们想要的结果是基类Person里面的成员变量age在子类和孙子类中都只保存一份.

#include <iostream>
using namespace::std;
class Person{
public:
    int age;
};
class Farmer:public Person{
public:
    void farm(){
        cout<< "农民种地"<<endl;
    }
};
class Worker:public Person{
public:
    
    void work() {
        cout<< "工人工作"<<endl;
    }
};
class FarmerWorker:public Farmer, public Worker {
    //农名工继承Farmer和worker,同事拥有2个类的方法
public:
    int age;
    void hardWork(){
        cout <<"农名工努力工作"<<endl;
    }
};
int main(int argc, const char * argv[]) {
    FarmerWorker fw = FarmerWorker();
    fw.Farmer::age = 10;//2个父类都有同名的成员age,通过命名空间区分.这个不是我们想要的结果,因为这个age都是从Person继承过来的.希望只得到一份age,而不是2份.解决方法是把Worker和Farmer都虚继承 Person,看后面的代码
    fw.Worker::age = 11;
    fw.age = 12;
    cout<< &fw.age <<endl; //普通的菱形继承,基类产生的成员变量被2个子类继承以后,到孙子类再继承,变成了不同的成员变量
    cout<< &fw.Farmer::age <<endl;
    cout<< &fw.Worker::age <<endl;
    cout << sizeof(fw) <<endl;
}

           

虚基类

继承关键字前面添加 virtual 就是虚继承 ,被虚继承的类,叫虚基类,例如下图Person被2个类虚继承, Person就是虚基类

虚继承

用virtual 关键字修饰的继承方式是虚继承,继承原理如下面图和代码所示.继承的成员变量只保存一份,而不是被保存多份.生成虚表

利用虚继承解决,保存多份不同成员变量的问题

c++中菱形继承中出现的问题和虚继承虚基类使用普通继承关系的菱形继承如下虚基类虚继承利用虚继承解决,保存多份不同成员变量的问题

先不要管图中虚表的问题,只看2个子类Farmer和Worker通过virtual关键字继承以后变成了虚继承,这样,内存空间中只保存了一份age成员变量,到了孙子类的继承也是只有一份age.这个就能解决我们要的,只保存一份基类成员变量的问题.

上面图的代码如下,代码证明到孙子类的FarmerWorker里面的3个age地址相同,只保存了一份age,问题解决.

#include <iostream>
using namespace::std;
class Person{ //虚基类,因为被2个类虚继承
public:
    int age;
//    int age2;
//    int age3;
    void show(){
        cout << "Person::show()"<<endl;
    }
};
class Farmer: virtual public Person{
public:
    int money;
    void farm(){
        cout<< "农民种地"<<endl;
    }
};
class Worker: virtual public Person{ //virtual关键字 虚继承,被继承的基类,成员变量只保存一份,放在内存最后
public:
    int Id;
    void work() {
        cout<< "工人工作"<<endl;
    }
};
class FarmerWorker:public Farmer, public Worker {
    //农名工继承Farmer和worker,同事拥有2个类的方法
public:
    void hardWork(){
        cout <<"农名工努力工作"<<endl;
    }
};
int main(int argc, const char * argv[]) {
    FarmerWorker fw = FarmerWorker();
    fw.age = 10;
    fw.Farmer::age = 20;
    fw.Worker::age = 30;
    cout<< "fw.age=" <<fw.age<<endl;
    cout<< "fw.Farmer::age=" <<fw.Farmer::age<<endl;
    cout<< "fw.Worker::age=" <<fw.Worker::age<<endl;
    cout << &fw.age << endl <<&fw.Farmer::age <<endl<< &fw.Worker::age<<endl;
    //虚继承以后3个age地址都是一样的,因为成员变量age是从虚基类里面继承过来的,只生成了一份
    /*
     fw中的的内存中布局如下
     Farmer的虚表地址
     Farmer的money
     Worker的虚表
     Worker的Id
     Person的age 4
     */
    cout << sizeof(fw) <<endl;
}

           

继续阅读