公有繼承(public)
- 基類的public和protected成員的通路屬性在派生類中保持不變,但基類的private成員不可直接通路;
- 派生類中的成員函數可以直接通路基類中的public和protected成員,但是不能直接通路基類的private成員;
- 通過派生類的對象隻能通路基類的public成員。
私有繼承(private)
- 基類的public和protected成員都以private身份出現在派生類中,但基類的private成員不可以直接通路;
- 派生類中的成員函數可以直接通路基類中的public和protected成員,但是不能直接通路基類的private成員;
- 通過派生類的對象不能通路基類的任何成員。
保護繼承(protected)
- 基類的public和protected成員都以protected身份出現在派生類中,但基類的private成員不可以直接通路;
- 派生類中的成員函數可以直接通路基類中的public和protected成員,但是不能直接通路基類的private成員;
- 通過派生類的對象不能通路基類的任何成員。
總結:
- 由上可見,三種繼承方式的差別在于對于基類的成員在繼承類中的通路屬性的不同改變方式。public繼承方式,基類成員在派生類中保持不變,private和protected方式将public和protected基類成員分别改變為private和protected通路屬性;
- 三種方式下繼承類中都不能直接通路基類的private成員;
- public方式下,派生類對象隻能通路基類的public成員(因為public成員通路屬性沒有改變),private和protected方式派生類對象不能通路基類任何成員(因為基類中的public和protected成員都被改成private或者protected通路屬性,都不能被執行個體化的對象直接通路,原因下述)。
protected成員的特點和作用
- 對建立其所在類對象的子產品來說,他與private成員的性質相同(都不能被對象通路);
- 對于其派生類來說,他的性質又與public成員性質相同(在派生類中使用時和public一樣可用);
- 即實作了資料隐藏,又友善繼承,實作代碼重用;
類型相容原則:
一個公有派生類對象在使用上可以被當作基類的對象,反之則禁止,具體表現在:
- 派生類的對象可以隐含轉換為基類對象;
- 派生類的對象可以初始化基類的引用;
- 派生類的指針可以隐含轉換為基類的指針;
通過基類對象名、指針隻能使用從基類繼承的成員。
例:
#include <iostream>
using namespace std;
class Base1 { //基類Base1定義
public:
void display() const {
cout << "Base1::display()" << endl;
}
};
class Base2: public Base1 { //公有派生類Base2定義
public:
void display() const {
cout << "Base2::display()" << endl;
}
};
class Derived: public Base2 { //公有派生類Derived定義
public:
void display() const {
cout << "Derived::display()" << endl;
}
};
void fun(Base1 *ptr) { //參數為指向基類對象的指針
ptr->display(); //"對象指針->成員名"
}
int main() { //主函數
Base1 base1; //聲明Base1類對象
Base2 base2; //聲明Base2類對象
Derived derived; //聲明Derived類對象
//用Base1對象的指針調用fun函數
fun(&base1);
//用Base2對象的指針調用fun函數
fun(&base2);
//用Derived對象的指針調用fun函數
fun(&derived);
return 0;
}
運作結果:
Base1::display()
Base1::display()
Base1::display()
拷貝構造函數
若建立派生類對象時沒有編寫拷貝構造函數,編譯器會自動生成一個隐含的拷貝構造函數,該函數先調用基類的拷貝構造函數,再為派生類新增的成員對象執行拷貝;
若編寫派生類的拷貝構造函數,則需要為基類相應的拷貝構造函數傳遞參數,例如:
C::C(C &c1):B(c1){...}