第一個規則:和公有繼承相反,如果兩個類之間的繼承關係爲私有,編譯器一般不會將派生類對象轉換成基類對象。
第二個規則: 從私有基類繼承而來的成員都成爲了派生類的私有成員,即使它們在基類中是保護或公有成員。
私有繼承的含義:私有繼承意味着 "用...來實現"。
如果使類D私有繼承於類B,這樣做是因爲你想利用類B中已經存在的某些代碼,而不是因爲類型B的對象和類型D的對象之間有什麼概念上的關係。
因而,私有繼承純粹是一種實現技術。
私有繼承意味着只是繼承實現,接口會被忽略。如果D私有繼承於B,就是說D對象在實現中用到了B對象,僅此而已。
私有繼承在軟件 "設計" 過程中毫無意義,只是在軟件 "實現" 時纔有用。
拿下面的這幾個類爲例:
class D_priv : private B { };
class D_prot : protected B { };
class D_publ : public B { };
class UserClass { B b; };
沒有一個派生類可以訪問 B 的 private 部分。
在 D_priv 中,B 的 public 和 protected 部分是 private 的。
在 D_prot 中,B 的 public 和 protected 部分是 protected 的。
在 D_publ 中,B 的 public 部分是 public,protected 部分是 protected,因爲 D_publ Is-A B。
UserClass 僅可訪問 B 的 public 部分,因爲 B 對內部實現進行了封裝。
要讓 B 的 public 方法在 D_priv 或 D_prot 中也是 public,需要使用 B:: 前綴,例:讓 B::f(int, float) 方法在 D_prot 也是 public,應該寫爲:
public:
using B::f; // Note: Not using B::f(int,float)
};
在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定義的類有更大的區別。實際上它們唯一的不同只是默認的成員保護級別和默認的派生保護級別(struct都爲public,class都爲private),除此之外,再也沒有其他的區別。
轉自:http://blog.sina.com.cn/s/blog_60cc33d70100xylq.html