在C++中繼承主要有三種關係:public、protected和private。這三種繼承關係中public繼承是最爲常用的一種繼承關係,private繼承是最少見的繼承關係。
1. public
從語義角度上來說,public繼承是一種接口繼承,根據面向對象中的關係而言就是,派生類可以代替基類完成基類接口所聲明的行爲,也就是必須符合“Liskov替換原則(LSP)”,此時派生類可以自動轉換成爲基類的接口,完成接口轉換。
從語法角度上來說,public繼承會保留基類中成員(包括函數和變量等)的可見性不變,也就是說,基類的public成員爲派生類的public成員,基類的protected成員爲派生類的protected成員。
2. protected
從語義角度上來說,protected繼承是一種實現繼承,根據面向對象中的關係而言就是,派生類不能代替基類完成基類接口所聲明的行爲,也就是不符合“Liskov替換原則(LSP)”,此時派生類不能自動轉換成爲基類的接口,就算通過類型轉換(static_cast和dynamic_cast)也會得到一個空指針。
從語法角度上來說,protected繼承會將基類中的public可見性的成員修改成爲protected可見性,相當於在派生類中引入了protected成員,這樣一來在派生類中同樣還是可以調用基類的protected和public成員,派生類的派生類就也可以調用被protected繼承的基類的protected和public成員。例如:
class CSample1 {
protected:
void printProtected() {}
public:
void printPublic() {}
};
class CSample2 : protected CSample1 {};
class CSample3 : public CSample2 {
void print3() {
printProtected();
printPublic();
}
};
3. private
從語義角度上來說,private繼承是一種實現繼承,根據面向對象中的關係而言就是,派生類不能代替基類完成基類接口所聲明的行爲,也就是不符合“Liskov替換原則(LSP)”,此時派生類不能自動轉換成爲基類的接口,就算通過類型轉換(static_cast和dynamic_cast)也會得到一個空指針。
從語法角度上來說,private繼承會將基類中的public和protected可見性的成員修改成爲private可見性,這樣一來雖然派生類中同樣還是可以調用基類的protected和public成員,但是在派生類的派生類就不可以再調用被private繼承的基類的成員了。
class CSample1 {
protected:
void printProtected() {}
public:
void printPublic() {}
};
class CSample2 : private CSample1 {};
class CSample3 : public CSample2 {
void print3() {
printProtected(); // 編譯錯誤,不可以調用該函數
printPublic(); // 編譯錯誤,不可以調用該函數
}
};
4. using聲明
如果進行private或protected繼承,則基類成員的訪問級別在派生類中比在基類中更受限:
class Base{
public:
std::size_t size() const {return n;}
protected:
std::size_t n;
}
class Derived : private Base{...};
在這一繼承層次中,size在Base中爲public,但在Derived中爲private。爲了使size在Derived中成爲public,可以在Derived的public部分增加一個using聲明。如下這樣改變Derived的定義,可以使size成員能夠被用戶訪問,並使n能夠被從Derived派生的類訪問:
class Derived : private Base{
public:
using Base::size;
privated:
using Base::n;
//...
}
用struct和class保留字定義的類具有不同的默認訪問級別。同樣,默認繼承訪問級別根據使用哪個保留字定義派生類也不相同。使用class保留字定義的派生類默認具有private繼承,而用struct保留字定義的類默認具有public繼承:
class Base{/*...*/}
struct D1 : Base{/*...*/}; //public inheritance by default
class D2 : Base{/*...*/}; //private inheritance by default
有一種常見的誤解認爲用struct保留字定義的類與用class定義的類有更大的區別。實際上它們唯一的不同只是默認的成員保護級別和默認的派生保護級別,除此之外,再也沒有其他的區別