單繼承與多繼承
單繼承:一個子類只一一個直接父類時稱這個繼承關係爲單繼承
多繼承:一個子類有兩個或者兩個以上直接父類時稱這個繼承關係爲多繼承。
菱形繼承:菱形繼承是多繼承的一種特殊情況。兩個子類同時繼承一個父類,又有一個子類繼承這兩個子類。
菱形繼承的問題:從下面的代碼可以看出,菱形繼承有數據冗餘和二義性的問題。
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.Student::_name = "yyy";
}
解決菱形繼承的二義性和數據冗餘的問題採用虛擬繼承。即在繼承時採用virtual關鍵字。虛擬繼承不用在其他地方去使用.
class A
{
public:
int _a;
};
class B :virtual public A
{
public:
int _b;
};
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;
}
通過以上代碼我們發現:
通過觀察內存發現,虛擬繼承中基類部分在下,子類部分在上與普通繼承是反的
B和C中存在兩個類似於地址的數據,其實是兩個指針,指向一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表。虛基表中存在偏移量,通過偏移量可以找到A。虛基表中第一個存在的是相對於自己的偏移量,第二個是相對於派生類的起始位置的偏移量
普通單繼承與虛擬繼承的區別?
1.普通虛擬繼承比普通的單繼承多了4個字節
2.虛擬繼承中基類部分在下,子類部分在上 與普通繼承是反的
3.編譯器會給派生類生成默認的構造函數-----------------要在對象的前4個字節放數據
4.對象前4個字節中的內容------------>指向一塊內存空間(0,8)