什么是菱形继承呢?虚继承有是如何解决菱形继承的二义性和数据冗余呢?
首先什么是单继承、什么是多继承?
单继承:一个子类只有一个直接父类时称这个继承关系为单继承
多继承:一个子类两个或两个以上直接父类时,称这个继承关系为多继承
菱形继承
菱形继承是多继承跑不掉的。两个子类继承同一个父类,而又有一个子类同时继承这两个子类。
eg:
class Person { public : string _name ; // 姓名 }; class Student : public Person { public : int _num ; //学号 }; class Teacher : public Person { public : int _id ; // 职工编号 }; class Assistant : public Student, public Teacher { public : string _majorCourse ; // 主修课程 };
分析:
由于student和Teacher都继承了Person,所以Student和Teacher中都存在_name,此时Assistant同时继承Student和Teacher,则Assistant中会存在两份_name ,当定义Assistant对象a去访问a._name时,由于不明确访问Student中的_name还是Teacher中的_name,这就产生
二义性,会出现访问不明确错误。
虚继承
C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。
虚继承解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
eg:
class Person { public : string _name ; // 姓名 }; class Student : public virtual Person { public : int _num ; //学号 }; class Teacher : public virtual Person { public : int _id ; // 职工编号 }; class Assistant : public Student, public Teacher { public : string _majorCourse ; // 主修课程 }; void Test () { Assistant a ; a._name = "xxx"; a._num = 1; a._id = 2; a._majorCourse = "yyy"; }
分析:
引进虚基类之后,派生类(子类)的对象中只存在一个虚基类的子对象;当一个类拥有虚基类的时候,编译系统会为这个类的对象定义一个指针成员,并让它指向虚基类的子对象;该指针被称为
虚基类指针; 这样的话,不同继承路径上的虚基类子对象在派生类中被合并成一个子对象了,这便是虚基类的作用,这样就可以消除合并之前出现的二义性问题。
注:
虚继承体系看起来好复杂,在实际应用我们通常不会定义如此复杂的继承体系。一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决数据冗余问题也带来了
性能上的损耗。