C++類繼承關系問題
在C++中繼承主要有三種關系:public、protected和private。這三種繼承關系中public
繼承是最為常用的一種繼承關系,代表了接口繼承含義,而他們分別具體代表了什么含義呢?
1. public
從語義角度上來說,public繼承是一種接口繼承,根據面向對象中的關系而言就是,子類
可以代替父類完成父類接口所聲明的行為,也就是必須符合“Liskov替換原則(LSP)”,
此時子類可以自動轉換成為父類的接口,完成接口轉換。
從語法角度上來說,public繼承會保留父類中成員(包括函數和變量等)的可見性不變,
也就是說,如果父類中的某個函數是public的,那么在被子類繼承后仍然是public的。
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(); // 編譯錯誤,不可以調用該函數
}
};
在面向對象的理論中有兩種概念:接口、實現,所以就出現了所謂的接口繼承和實現繼
承兩種關系。而protected和private就是實現繼承中所要用到的,其實protected和private
兩者則約束繼承時并沒有形成兩種不同的繼承類別,而僅僅只是為了方便C++類方法的傳遞
調用而設計的,其實在java這樣面向對象要求更為嚴格的語言當中,沒有實現繼承,他必須
通過委托方式來完成這一概念,如果熟悉java就會明白,如果一個對象要使用另外一個對象
的接口功能,而自身又不能夠充當該對象所扮演的角色時,就會通過委托來完成,這樣一來
就必須在對象中包含一個委托對象,通過對象調用語法來完成功能;在C++中就可以通過
protected和private繼承來完成java中的委托關系(當然C++也可以形成對象委托關系),
那么這種情況下protected繼承就容許委托可以傳遞(也就是被多級子類調用),而private
繼承是不容許委托被傳遞的。
在C++中繼承主要有三種關系:public、protected和private。這三種繼承關系中public
繼承是最為常用的一種繼承關系,代表了接口繼承含義,而他們分別具體代表了什么含義呢?
1. public
從語義角度上來說,public繼承是一種接口繼承,根據面向對象中的關系而言就是,子類
可以代替父類完成父類接口所聲明的行為,也就是必須符合“Liskov替換原則(LSP)”,
此時子類可以自動轉換成為父類的接口,完成接口轉換。
從語法角度上來說,public繼承會保留父類中成員(包括函數和變量等)的可見性不變,
也就是說,如果父類中的某個函數是public的,那么在被子類繼承后仍然是public的。
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(); // 編譯錯誤,不可以調用該函數
}
};
在面向對象的理論中有兩種概念:接口、實現,所以就出現了所謂的接口繼承和實現繼
承兩種關系。而protected和private就是實現繼承中所要用到的,其實protected和private
兩者則約束繼承時并沒有形成兩種不同的繼承類別,而僅僅只是為了方便C++類方法的傳遞
調用而設計的,其實在java這樣面向對象要求更為嚴格的語言當中,沒有實現繼承,他必須
通過委托方式來完成這一概念,如果熟悉java就會明白,如果一個對象要使用另外一個對象
的接口功能,而自身又不能夠充當該對象所扮演的角色時,就會通過委托來完成,這樣一來
就必須在對象中包含一個委托對象,通過對象調用語法來完成功能;在C++中就可以通過
protected和private繼承來完成java中的委托關系(當然C++也可以形成對象委托關系),
那么這種情況下protected繼承就容許委托可以傳遞(也就是被多級子類調用),而private
繼承是不容許委托被傳遞的。