C++:13---繼承(單一繼承、多重繼承、多級繼承、菱形繼承、虛繼承)
阿新 • • 發佈:2020-12-23
一、基類與派生類的概念
基類(父類):在繼承關係中處於上層的類
派生類(子類):在繼承關係中處於下層的類
class A;class B;class C:public A //C為A的子類,A為C的父類{};class D:public A,public B //D為A和B的子類,A和B均為D的父類{};
二、類派生列表
派生類通過派生類列表來指出其從哪個(哪些)基類繼承而來
類派生列表的使用規則:
①派生列表不能出現在類的宣告時,只能在定義時,原因如下:
一條宣告語句的目的是讓程式知曉某個名字的存在已經改名字表示一個什麼樣的實體(如一個類、一個函式、或一個變數等)
class A;
class B;
//class B:public A; 錯誤
class A{};
class B:public A{}; //正確
②要繼承的基類必須在本類之前定義而非宣告,原因如下:
派生類必須知道其從基類繼承而來的成員是什麼,如果基類只是一個宣告,那麼派生類將無從知曉
class A; //宣告
class B:public A{}; //錯誤
class A{};
③一個類不能派生其自身,原因和②是相同的
三、繼承的基本特點
①一個類可以被多個類繼承
②一個類也可以繼承於多個類
四、單一繼承
一個類只繼承於一個類叫做單一繼承
classA{}; classB:publicA//單一繼承{};
五、多重繼承
一個類只繼承於多個類叫做多重繼承
class A{};
class B {};
class C :public B, public A //多重繼承
{
};
六、多級繼承
一個子類還可以作為另一個類的父類而派生出另一個子類。在巨集觀上叫做多級繼承
class A{};
class B :public A
{};
class C :public B
{
};
七、菱形繼承
概念:A作為基類,B和C都繼承與A。最後一個類D又繼承於B和C,這樣形式的繼承稱為菱形繼承
菱形繼承的缺點:
資料冗餘:在D中會儲存兩份A的內容
訪問不明確(二義性):因為D不知道是以B為中介去訪問A還是以C為中介去訪問A,因此在訪問某些成員的時候會發生二義性
缺點的解決:
資料冗餘:通過下面“虛繼承”技術來解決(見下)
訪問不明確(二義性):通過作用域訪問符::來明確呼叫。虛繼承也可以解決這個問題
演示案例
class A{public:A(int a) :m_a(a) {}int getMa() { return m_a; }private:int m_a;};class B :public A{public:B(int a, int b) :A(a), m_b(b) {}private:int m_b;};class C :public A{public:C(int a, int c) :A(a), m_c(c) {}private:int m_c;};class D :public B, public C{public:D(int a, int b, int c, int d) :B(a, b), C(a, c), m_d(d) {}void func(){/*錯誤,訪問不明確 std::cout << getMa();*///正確,通過B訪問getMa()std::cout << B::getMa();}private:int m_d;};
八、虛繼承
虛繼承的作用:為了保證公共繼承物件在建立時只儲存一分例項
虛繼承解決了菱形繼承的兩個問題:
資料冗餘:頂級基類在整個體系中只儲存了一份例項
訪問不明確(二義性):可以不通過作用域訪問符::來呼叫(原理就是因為頂級基類在整個體系中只儲存了一份例項)
虛繼承不常用,也不建議使用
class A{public:A(int a) :m_a(a) {}int getMa() { return m_a; }private:int m_a;};class B :virtual public A{public:B(int a, int b) :A(a), m_b(b) {}private:int m_b;};class C :virtual public A{public:C(int a, int c) :A(a), m_c(c) {}private:int m_c;};class D :virtual public B, virtual public C{public:D(int a, int b, int c, int d) :B(a, b), C(a, c), m_d(d) {}void func(){//都正確,因為A的內容在整個繼承體系中只儲存了一份std::cout << getMa();std::cout << A::getMa();}private:int m_d;};