單繼承和多繼承
單繼承:一個派生類隻有一個直接基類。
(B的直接父類隻有A,是單繼承)
class AA
{
public:
AA(int a=)
:_a(a)
{
cout << "AA()" << endl;
}
int _a;
};
class BB : public AA
{
public:
BB(int b=)
:_b(b)
{
cout << "BB()" << endl;
}
int _b;
};
多繼承:一個派生類的直接基類至少有兩個。
(C類不僅繼承了A類,還繼承了B類,是多繼承)
class CC : public AA ,public BB
{
public:
CC(int c=)
:_c(c)
{
cout << "CC()" << endl;
}
int _c;
};
菱形繼承屬于多繼承。
#include<iostream>
#include<stdlib.h>
using namespace std;
class A
{
public:
A(int a=)
:_a(a)
{
cout << "A()" << endl;
}
int _a;
};
class B : public A
{
public:
B(int b=)
:_b(b)
{
cout << "B()" << endl;
}
int _b;
};
class C : public A
{
public:
C(int c=)
:_c(c)
{
cout << "C()" << endl;
}
int _c;
};
class D : public B, public C
{
public:
D(int d=)
:_d(d)
{
cout << "D()" << endl;
}
int _d;
};
int main()
{
D d;
d._a;
}
對上面代碼進行編譯,發現不通過,錯誤如下:

這個是菱形繼承存在的二義性的問題。
從圖中可以看出來,在D類中B類和C類分别存了一份A類的成員變量,造成了資料備援的問題。
二義性問題可以通過指定類域進行通路,但是這樣太麻煩,而且資料備援的問題并沒有得到解決。針對這個問題C++引入了虛繼承。
虛繼承:繼承的前面加上virtual.
形如:class 派生類名:virtual 繼承方式 基類名
(virtual為關鍵字,聲明該基類為派生類的虛基類)
#include<iostream>
#include<stdlib.h>
using namespace std;
class A
{
public:
A(int a=)
:_a(a)
{
cout << "A()" << endl;
}
int _a;
};
class B : virtual public A
{
public:
B(int b=)
:_b(b)
{
cout << "B()" << endl;
}
int _b;
};
class C : virtual public A
{
public:
C(int c=)
:_c(c)
{
cout << "C()" << endl;
}
int _c;
};
class D : public B, public C
{
public:
D(int d=)
:_d(d)
{
cout << "D()" << endl;
}
int _d;
};
int main()
{
D d;
}
虛繼承的記憶體分布有所變化,這裡将公共的A類成員變量單獨存起來,以前存A類成員變量的地方存了虛基類的位址,這個位址存的是A類成員變量距派生類位址的偏移量。
雖然虛繼承解決了菱形繼承二義性和資料備援的問題,但是性能上會有所影響。
沒有使用虛繼承時,sizeof(d)=20;
使用虛繼承後,sizeof(d)=24.