詳解C++編程中的私有繼承和公有繼承
C++類的私有繼承
在聲明一個派生類時(shí)將基類的繼承方式指定為private的,稱為私有繼承,用私有繼承方式建立的派生類稱為私有派生類(private derived class ), 其基類稱為私有基類(private base class )。
私有基類的公用成員和保護(hù)成員在派生類中的訪問屬性相當(dāng)于派生類中的私有成員,即派生類的成員函數(shù)能訪問它們,而在派生類外不能訪問它們。私有基類的私有成員在派生類中成為不可訪問的成員,只有基類的成員函數(shù)可以引用它們。一個基類成員在基類中的訪問屬性和在派生類中的訪問屬性可能是不同的。私有基類的成員在私有派生類中的訪問屬性見下表。
上表不必死記硬背,只需理解:既然聲明為私有繼承,就表示將原來能被外界引用的成員隱藏起來,不讓外界引用,因此私有基類的公用成員和保護(hù)成員理所當(dāng)然地成為派生類中的私有成員。
私有基類的私有成員按規(guī)定只能被基類的成員函數(shù)引用,在基類外當(dāng)然不能訪問他們,因此它們在派生類中是隱蔽的,不可訪問的。
對于不需要再往下繼承的類的功能可以用私有繼承方式把它隱蔽起來,這樣,下一層的派生類無法訪問它的任何成員??梢灾?,一個成員在不同的派生層次中的訪問屬性可能是不同的,它與繼承方式有關(guān)。
[例]
class Student1: private Student//用私有繼承方式聲明派生類Student1 { public: void display_1( ) //輸出兩個數(shù)據(jù)成員的值 { cout<<"age: "<<age<<endl; //引用派生類的私有成員,正確 cout<<"address: "<<addr<<endl; } //引用派生類的私有成員,正確 private: int age; string addr; };
請分析下面的主函數(shù):
int main( ) { Student1 stud1;//定義一個Student1類的對象stud1 stud1.display(); //錯誤,私有基類的公用成員函數(shù)在派生類中是私有函數(shù) stud1.display_1( );//正確,Display_1函數(shù)是Student1類的公用函數(shù) stud1.age=18; //錯誤,外界不能引用派生類的私有成員 return 0; }
可以看到:
不能通過派生類對象(如stud1)引用從私有基類繼承過來的任何成員(如stud1.display()或stud1.num)。
派生類的成員函數(shù)不能訪問私有基類的私有成員,但可以訪問私有基類的公用成員(如stud1.display_1函數(shù)可以調(diào)用基類的公用成員函數(shù)display,但不能引用基類的私有成員num)。
不少讀者提出這樣一個問題:私有基類的私有成員mun等數(shù)據(jù)成員只能被基類的成員函數(shù)引用,而私有基類的公用成員函數(shù)又不能被派生類外調(diào)用,那么,有沒有辦法調(diào)用私有基類的公用成員函數(shù),從而引用私有基類的私有成員呢?有。
應(yīng)當(dāng)注意到,雖然在派生類外不能通過派生類對象調(diào)用私有基類的公用成員函數(shù),但可以通過派生類的成員函數(shù)調(diào)用私有基類的公用成員函數(shù)(此時(shí)它是派生類中的私有成員函數(shù),可以被派生類的任何成員函數(shù)調(diào)用)。
可將上面的私有派生類的成員函數(shù)定義改寫為:
void display_1( )//輸出5個數(shù)據(jù)成員的值 { display(): //調(diào)用基類的公用成員函數(shù),輸出3個數(shù)據(jù)成員的值 cout<<"age: "<<age<<endl; //輸出派生類的私有數(shù)據(jù)成員 cout<<"address: "<<addr<<endl; } //輸出派生類的私有數(shù)據(jù)成員
main函數(shù)可改寫為:
int main( ) { Student1 stud1; stud1.display_1( );//display_1函數(shù)是派生類Student1類的公用函數(shù) return 0; }
這樣就能正確地引用私有基類的私有成員??梢钥吹剑纠捎玫姆椒ㄊ牵?br />
在main函數(shù)中調(diào)用派生類中的公用成員函數(shù)stud1.display_1;
通過該公用成員函數(shù)調(diào)用基類的公用成員函數(shù)display(它在派生類中是私有函數(shù),可以被派生類中的任何成員函數(shù)調(diào)用);
通過基類的公用成員函數(shù)display引用基類中的數(shù)據(jù)成員。
請根據(jù)上面的要求,補(bǔ)充和完善上面的程序,使之成為完整、正確的程序,程序中應(yīng)包括輸入數(shù)據(jù)的函數(shù)。
由于私有派生類限制太多,使用不方便,一般不常使用。
C++類的公用繼承
在定義一個派生類時(shí)將基類的繼承方式指定為public的,稱為公用繼承,用公用繼承方式建立的派生類稱為公用派生類(public derived class ),其基類稱為公用基類(public base class )。
采用公用繼承方式時(shí),基類的公用成員和保護(hù)成員在派生類中仍然保持其公用成員和保護(hù)成員的屬性,而基類的私有成員在派生類中并沒有成為派生類的私有成員,它仍然是基類的私有成員,只有基類的成員函數(shù)可以引用它,而不能被派生類的成員函數(shù)引用,因此就成為派生類中的不可訪問的成員。公用基類的成員在派生類中的訪問屬性見表。
有人問,既然是公用繼承,為什么不讓訪問基類的私有成員呢?要知道,這是C++中一個重要的軟件工程觀點(diǎn)。因?yàn)樗接谐蓡T體現(xiàn)了數(shù)據(jù)的封裝性,隱藏私有成員有利于測試、調(diào)試和修改系統(tǒng)。如果把基類所有成員的訪問權(quán)限都原封不動地繼承到派生類,使基類的私有成員在派生類中仍保持其私有性質(zhì),派生類成員能訪問基類的私有成員,那么豈非基類和派生類沒有界限了?這就破壞了基類的封裝性。如果派生類再繼續(xù)派生一個新的派生類,也能訪問基類的私有成員,那么在這個基類的所有派生類的層次上都能訪問基類的私有成員,這就完全丟棄了封裝性帶來的好處。保護(hù)私有成員是一條重要的原則。
[例] 訪問公有基類的成員。下面寫出類的聲明部分:
Class Student//聲明基類 { public: //基類公用成員 void get_value( ) { cin>>num>>name>>sex; } void display( ) { cout<<" num: "<<num<<endl; cout<<" name: "<<name<<endl; cout<<" sex: "<<sex<<endl; } private: //基類私有成員 int num; string name; char sex; }; class Student1: public Student //以public方式聲明派生類Student1 { public: void display_1( ) { cout<<" num: "<<num<<endl; //企圖引用基類的私有成員,錯誤 cout<<" name: "<<name<<endl; //企圖引用基類的私有成員,錯誤 cout<<" sex: "<<sex<<endl; //企圖引用基類的私有成員,錯誤 cout<<" age: "<<age<<endl; //引用派生類的私有成員,正確 cout<<" address: "<<addr<<endl; } //引用派生類的私有成員,正確 private: int age; string addr; };
由于基類的私有成員對派生類來說是不可訪問的,因此在派生類中的display_1函數(shù)中直接引用基類的私有數(shù)據(jù)成員num,name和sex是不允許的。只能通過基類的公用成員函數(shù)來引用基類的私有數(shù)據(jù)成員??梢詫⑴缮怱tudent1的聲明改為
class Student1: public Student //以public方式聲明派生類Student1 { public: void display_1( ) { cout<<" age: "<<age<<endl; //引用派生類的私有成員,正確 cout<<" address: "<<addr<<endl; //引用派生類的私有成員,正確 } private: int age; string addr; };
然后在main函數(shù)中分別調(diào)用基類的display函數(shù)和派生類中的display_1函數(shù),先后輸出5個數(shù)據(jù)。
可以這樣寫main函數(shù)(假設(shè)對象stud中已有數(shù)據(jù)):
int main( ) { Student1 stud;//定義派生類Student1的對象stud stud.display( ); //調(diào)用基類的公用成員函數(shù),輸出基類中3個數(shù)據(jù)成員的值 stud.display_1(); //調(diào)用派生類公用成員函數(shù),輸出派生類中兩個數(shù)據(jù)成員的值 return 0; }
請根據(jù)上面的分析,寫出完整的程序,程序中應(yīng)包括輸入數(shù)據(jù)的函數(shù)。
實(shí)際上,程序還可以改進(jìn),在派生類的display_1函數(shù)中調(diào)用基類的display函數(shù),在主函數(shù)中只要寫一行:
stud.display_1();
即可輸出5個數(shù)據(jù)。
相關(guān)文章
Qt連接MySQL數(shù)據(jù)庫的實(shí)現(xiàn)(保姆級成功版教程)
本文主要介紹了Qt連接MySQL數(shù)據(jù)庫的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C語言詳解如何實(shí)現(xiàn)帶頭雙向循環(huán)鏈表
帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨(dú)存儲數(shù)據(jù)。實(shí)際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實(shí)現(xiàn)以后會發(fā)現(xiàn)結(jié)構(gòu)會帶來很多優(yōu)勢,實(shí)現(xiàn)反而簡單2022-04-04基于Qt制作一個定時(shí)關(guān)機(jī)的小程序
這篇文章主要為大家詳細(xì)介紹了如何基于Qt制作一個有趣的定時(shí)關(guān)機(jī)的小程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12