普通继承关系的菱形继承如下
基类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 关键字修饰的继承方式是虚继承,继承原理如下面图和代码所示.继承的成员变量只保存一份,而不是被保存多份.生成虚表
利用虚继承解决,保存多份不同成员变量的问题
先不要管图中虚表的问题,只看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;
}