天天看點

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;
}

           

繼續閱讀