目錄
一,菱形繼承
1.1單繼承
1.2多繼承
1.3菱形繼承
1.4菱形繼承的問題
1.5虛擬繼承解決數據冗余和二義性的原理
二.繼承的總結和反思
一,菱形繼承
C++三大特性——繼承-CSDN博客
1.1單繼承
單繼承:一個子類只有一個直接父類時稱這個繼承關系為單繼承
1.2多繼承
多繼承:一個子類有兩個或以上直接父類時稱這個繼承關系為多繼承
1.3菱形繼承
菱形繼承:菱形繼承是多繼承的一種特殊情況
1.4菱形繼承的問題
菱形繼承的問題:從下面的對象成員模型構造,可以看出菱形繼承有數據冗余和二義性的問題。在Assistant的對象中Person成員會有兩份。
class Person
{
public:string _name; // 姓名
};
class Student : public Person
{
protected:int _num; //學號
};
class Teacher : public Person
{
protected:int _id; // 職工編號
};
class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};
void Test()
{// 這樣會有二義性無法明確知道訪問的是哪一個Assistant a;//a._name = "peter"; 錯誤// 需要顯示指定訪問哪個父類的成員可以解決二義性問題,但是數據冗余問題無法解決a.Student::_name = "xxx";a.Teacher::_name = "yyy";
}
虛擬繼承可以解決菱形繼承的二義性和數據冗余的問題。如上面的繼承關系,在Student和Teacher的繼承Person時使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用
class Person
{
public:string _name; // 姓名
};
class Student : virtual public Person
{
protected:int _num; //學號
};
class Teacher : virtual public Person
{
protected:int _id; // 職工編號
};
class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};
void Test()
{Assistant a;a._name = "peter";
}
1.5虛擬繼承解決數據冗余和二義性的原理
為了研究虛擬繼承原理,我們給出了一個簡化的菱形繼承繼承體系,再借助內存窗口觀察對象成員的模型。
class A
{
public:int _a;
};
// class B : public A
class B : virtual public A
{
public:int _b;
};
// class C : public A
class C : virtual public A
{
public:int _c;
};
class D : public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}
下圖是菱形繼承的內存對象成員模型:這里可以看到數據冗余
下圖是菱形虛擬繼承的內存對象成員模型:這里可以分析出D對象中將A放到的了對象組成的最下面,這個A同時屬于B和C,那么B和C如何去找到公共的A呢?這里是通過了B和C的兩個指針,指向的一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表。虛基表中存的偏移量。通過偏移量可以找到下面的A。
// 有人可能會有疑問為什么D中B和C部分要去找屬于自己的A?那么大家看看當下面的賦值發生時,d是不是
要去找出B/C成員中的A才能賦值過去?
D d;
B b = d;
C c = d;
下面是上面的Person關系菱形虛擬繼承的原理解釋:
二.繼承的總結和反思
1. 很多人說C++語法復雜,其實多繼承就是一個體現。有了多繼承,就存在菱形繼承,有了菱形繼承就有菱形虛擬繼承,底層實現就很復雜。所以一般不建議設計出多繼承,一定不要設計出菱形繼承。否則在復雜度及性能上都有問題。
2. 多繼承可以認為是C++的缺陷之一,很多后來的語言都沒有多繼承,如Java