




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
類的繼承和派生第一頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類classPerson{ stringIdPerson; //身份證號,18位數(shù)字
stringName; //姓名
boolSex; //性別
int Birthday; //格式1986年8月18日寫作19860818 stringHomeAddress; //家庭地址public: Person(string,string,Tsex,int,string);//構(gòu)造函數(shù)
Person(); //默認(rèn)的構(gòu)造函數(shù)
~Person(); //析構(gòu)函數(shù)第二頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類voidSetName(string);
//修改名字
stringGetName(){returnName;}
//提取名字
voidSetSex(Tsexsex){Sex=sex;} //修改性別
boolGetSex(){returnSex;} //提取性別
voidSetId(stringid){IdPerson=id;} //修改身份證號
stringGetId(){returnIdPerson;}
//提取身份證號
voidSetBirth(intbirthday){Birthday=birthday;}//修改生日
int GetBirth(){returnBirthday;}//提取生日
voidSetHomeAdd(string); //修改住址
stringGetHomeAdd(){returnHomeAddress;}
//提取住址
voidPrintInfo(); //打印個人信息};//接口函數(shù):第三頁,共一百一十一頁,編輯于2023年,星期五繼承(inheritance):該機(jī)制是面向?qū)ο蟪绦蛟O(shè)計使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能。這樣產(chǎn)生新的類,稱派生類。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計的層次結(jié)構(gòu)。體現(xiàn)了由簡單到復(fù)雜的認(rèn)識過程。第八章繼承與多態(tài)多態(tài)性(polymorphism):多態(tài)性是考慮在不同層次的類中,以及在同一類中,同名的成員函數(shù)之間的關(guān)系問題。函數(shù)的重載,運(yùn)算符的重載,屬于編譯時的多態(tài)性。以虛函數(shù)為基礎(chǔ)的運(yùn)行時的多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的標(biāo)志性特征。體現(xiàn)了類推和比喻的思想方法。
第四頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類classPerson{ stringIdPerson; //身份證號,18位數(shù)字
stringName; //姓名
boolSex; //性別
int Birthday; //格式1986年8月18日寫作19860818 stringHomeAddress; //家庭地址public: Person(string,string,Tsex,int,string);//構(gòu)造函數(shù)
Person(); //默認(rèn)的構(gòu)造函數(shù)
~Person(); //析構(gòu)函數(shù)第五頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類voidSetName(string);
//修改名字
stringGetName(){returnName;}
//提取名字
voidSetSex(Tsexsex){Sex=sex;} //修改性別
TsexGetSex(){returnSex;} //提取性別
voidSetId(stringid){IdPerson=id;} //修改身份證號
stringGetId(){returnIdPerson;}
//提取身份證號
voidSetBirth(intbirthday){Birthday=birthday;}//修改生日
int GetBirth(){returnBirthday;}//提取生日
voidSetHomeAdd(string); //修改住址
stringGetHomeAdd(){returnHomeAddress;}
//提取住址
virtualvoidPrintInfo(); //打印個人信息};//接口函數(shù):第六頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類派生的學(xué)生類:classStudent:publicPerson //定義派生的學(xué)生類{stringNoStudent;//學(xué)號
coursecs[30];//30門課程與成績public:Student(stringid,stringname,Tsexsex,intbirthday, stringhomeadd,stringnostud);
//注意派生類構(gòu)造函數(shù)聲明方式
Student(); //默認(rèn)派生類構(gòu)造函數(shù)
~Student(); //派生類析構(gòu)函數(shù)
SetCourse(string,int); //課程設(shè)置
intGetCourse(string); //查找成績
voidPrintInfo(); //打印學(xué)生情況};structcourse{stringcoursename;
intgrade;};第七頁,共一百一十一頁,編輯于2023年,星期五第八章繼承與多態(tài)8.1繼承與派生的概念
8.4虛基類(選讀)
8.3多重繼承與派生類成員標(biāo)識
8.6多態(tài)性與虛函數(shù)
8.5派生類應(yīng)用討論
8.2派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)
第八頁,共一百一十一頁,編輯于2023年,星期五8.1
繼承與派生的概念
層次概念是計算機(jī)的重要概念。通過繼承(inheritance)的機(jī)制可對類(class)分層,提供類型/子類型的關(guān)系。
C++通過類派生(classderivation)的機(jī)制來支持繼承。被繼承的類稱為基類(baseclass)或超類(superclass),新的類為派生類(derivedclass)或子類(subclass)。基類和派生類的集合稱作類繼承層次結(jié)構(gòu)(hierarchy)。
如果基類和派生類共享相同的公有接口,則派生類被稱作基類的子類型(subtype)。
層次概念:派生反映了事物之間的聯(lián)系,事物的共性與個性之間的關(guān)系。派生與獨(dú)立設(shè)計若干相關(guān)的類,前者工作量少,重復(fù)的部分可以從基類繼承來,不需要單獨(dú)編程。第九頁,共一百一十一頁,編輯于2023年,星期五8.1
繼承與派生的概念8.1.1類的派生與繼承
8.1.2公有派生與私有派生
第十頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類派生的學(xué)生類:classStudent:publicPerson //定義派生的學(xué)生類{stringNoStudent;//學(xué)號
coursecs[30];//30門課程與成績public:Student(stringid,stringname,Tsexsex,intbirthday, stringhomeadd,stringnostud);
//注意派生類構(gòu)造函數(shù)聲明方式
Student(); //默認(rèn)派生類構(gòu)造函數(shù)
~Student(); //派生類析構(gòu)函數(shù)
SetCourse(string,int); //課程設(shè)置
intGetCourse(string); //查找成績
voidPrintInfo(); //打印學(xué)生情況};structcourse{stringcoursename;
intgrade;};第十一頁,共一百一十一頁,編輯于2023年,星期五派生類的定義:class派生類名:訪問限定符基類名1《,訪問限定符基類名2,……,訪問限定符基類名n》{《《private:》
成員表1;》
//派生類增加或替代的私有成員《public:
成員表2;》
//派生類增加或替代的公有成員《protected:
成員表3;》
//派生類增加或替代的保護(hù)成員};//分號不可少其中基類1,基類2,……是已聲明的類。在派生類定義的類體中給出的成員稱為派生類成員,它們是新增加成員,它們給派生類添加了不同于基類的新的屬性和功能。派生類成員也包括取代基類成員的更新成員。8.1.1類的派生與繼承第十二頁,共一百一十一頁,編輯于2023年,星期五基類1基類2……基類n派生類1派生類2基類派生類1派生類2(a)多重繼承
(b)單繼承
圖8.1多重繼承與單繼承
一個基類可以直接派生出多個派生類
派生類可以由多個基類共同派生出來,稱多重繼承。8.1.1類的派生與繼承多重繼承:如果一個派生類可以同時有多個基類,稱為多重繼承(multiple-inheritance),這時的派生類同時得到了多個已有類的特征。單繼承:派生類只有一個直接基類的情況稱為單繼承(single-inheritance)。第十三頁,共一百一十一頁,編輯于2023年,星期五8.1.1類的派生與繼承
在派生過程中,派生出來的新類同樣可以作為基類再繼續(xù)派生出更新的類,依此類推形成一個層次結(jié)構(gòu)。直接參與派生出某類稱為直接基類,而基類的基類,以及更深層的基類稱為間接基類。類族:
同時一個基類可以直接派生出多個派生類。這樣形成了一個相互關(guān)聯(lián)的類族。如MFC就是這樣的族類,它由一個CObject類派生出200個MFC類中的絕大多數(shù)。多層次繼承:第十四頁,共一百一十一頁,編輯于2023年,星期五編制派生類時可分四步
吸收基類的成員
改造基類成員
發(fā)展新成員
重寫構(gòu)造函數(shù)與析構(gòu)函數(shù)
8.1.1類的派生與繼承不論是數(shù)據(jù)成員,還是函數(shù)成員,除構(gòu)造函數(shù)與析構(gòu)函數(shù)外全盤接收
聲明一個和某基類成員同名的新成員,派生類中的新成員就屏蔽了基類同名成員稱為同名覆蓋(override)派生類新成員必須與基類成員不同名,它的加入保證派生類在功能上有所發(fā)展。派生編程步驟:第十五頁,共一百一十一頁,編輯于2023年,星期五8.1.1類的派生與繼承第二步中,新成員如是成員函數(shù),參數(shù)表也必須一樣,否則是重載。第三步中,獨(dú)有的新成員才是繼承與派生的核心特征。第四步是重寫構(gòu)造函數(shù)與析構(gòu)函數(shù),派生類不繼承這兩種函數(shù)。不管原來的函數(shù)是否可用一律重寫可免出錯(?????)。訪問控制:亦稱為繼承方式,是對基類成員進(jìn)一步的限制。訪問控制也是三種:公有(public)方式,亦稱公有繼承保護(hù)(protected)方式,亦稱保護(hù)繼承私有(private)方式,亦稱私有繼承。
第十六頁,共一百一十一頁,編輯于2023年,星期五8.1.2公有派生與私有派生訪問限定符兩方面含義:派生類成員(新增成員)函數(shù)對基類(繼承來的)成員的訪問(調(diào)用和操作),和從派生類對象之外對派生類對象中的基類成員的訪問。classStudent:publicPerson{……public: Student(stringid,stringname,Tsexsex,int birthday,stringhomeadd,stringnostud);};classPerson{private:
stringName; //姓名public: stringGetName(){returnName;} //提取名字 ……}
第十七頁,共一百一十一頁,編輯于2023年,星期五8.1.2公有派生與私有派生不可直接訪問
不可直接訪問
private不可直接訪問
privateprotected不可直接訪問
privatepublic私有派生
不可直接訪問
不可直接訪問
private不可直接訪問
protectedprotected可直接訪問
publicpublic公有派生
在派生類對象外訪問派生類對象的基類成員
在派生類中對基類成員的訪問限定
基類中的訪問限定
派生方式
公有派生是絕對主流。第十八頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類//注意Person參數(shù)表不用類型Student::Student(stringid,stringname,Tsexsex,intbirthday,stringhomeadd,stringnostud):Person(id,name,sex,birthday,homeadd){ NoStudent=nostud;
for(inti=0;i<30;i++) //課程與成績清空
{ cs[i].coursename="#"; cs[i].grade=0; }}派生類構(gòu)造函數(shù):第十九頁,共一百一十一頁,編輯于2023年,星期五派生類構(gòu)造函數(shù)的定義:派生類名::派生類名(參數(shù)總表):基類名1(參數(shù)名表1)《,基類名2(參數(shù)名表2),……,基類名n(參數(shù)名表n)》,《成員對象名1(成員對象參數(shù)名表1),……,成員對象名m(成員對象參數(shù)名表m)》{…… //派生類新增成員的初始化;} //所列出的成員對象名全部為新增成員對象的名字注意:在構(gòu)造函數(shù)的聲明中,冒號及冒號以后部分必須略去。
所謂不能繼承并不是不能利用,而是把基類的構(gòu)造函數(shù)作為新的構(gòu)造函數(shù)的一部分,或者講調(diào)用基類的構(gòu)造函數(shù)?;惷麅H指直接基類,寫了底層基類,編譯器認(rèn)為出錯。
冒號后的基類名,成員對象名的次序可以隨意,這里的次序與調(diào)用次序無關(guān)。
8.2派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)第二十頁,共一百一十一頁,編輯于2023年,星期五派生類構(gòu)造函數(shù)各部分執(zhí)行次序:
1.調(diào)用基類構(gòu)造函數(shù),按它們在派生類定義的先后順序,順序調(diào)用。
2.調(diào)用成員對象的構(gòu)造函數(shù),按它們在類定義中聲明的先后順序,順序調(diào)用。3.派生類的構(gòu)造函數(shù)體中的操作。8.2派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)注意:在派生類構(gòu)造函數(shù)中,只要基類不是使用無參的默認(rèn)構(gòu)造函數(shù)都要顯式給出基類名和參數(shù)表。如果基類沒有定義構(gòu)造函數(shù),則派生類也可以不定義,全部采用系統(tǒng)給定的默認(rèn)構(gòu)造函數(shù)。如果基類定義了帶有形參表的構(gòu)造函數(shù)時,派生類就應(yīng)當(dāng)定義構(gòu)造函數(shù)。第二十一頁,共一百一十一頁,編輯于2023年,星期五8.2派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)析構(gòu)函數(shù):析構(gòu)函數(shù)的功能是作善后工作。
只要在函數(shù)體內(nèi)把派生類新增一般成員處理好就可以了,而對新增的成員對象和基類的善后工作,系統(tǒng)會自己調(diào)用成員對象和基類的析構(gòu)函數(shù)來完成。析構(gòu)函數(shù)各部分執(zhí)行次序與構(gòu)造函數(shù)相反,首先對派生類新增一般成員析構(gòu),然后對新增對象成員析構(gòu),最后對基類成員析構(gòu)。第二十二頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類【例8.1】由在冊人員類公有派生學(xué)生類。我們希望基類和派生類共享相同的公有接口,只能采用公有派生來實(shí)現(xiàn)?;悾篹num
Tsex{mid,man,woman};
classPerson{ stringIdPerson; //身份證號,18位數(shù)字
stringName; //姓名
TsexSex; //性別
intBirthday; //格式1986年8月18日寫作19860818 stringHomeAddress; //家庭地址public: Person(string,string,Tsex,int,string); //構(gòu)造函數(shù)
Person(); //默認(rèn)的構(gòu)造函數(shù)
~Person(); //析構(gòu)函數(shù)第二十三頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類
voidSetName(string);
//修改名字
stringGetName(){returnName;}
//提取名字
voidSetSex(Tsexsex){Sex=sex;} //修改性別
TsexGetSex(){returnSex;} //提取性別
voidSetId(stringid){IdPerson=id;} //修改身份證號
stringGetId(){returnIdPerson;}
//提取身份證號
voidSetBirth(intbirthday){Birthday=birthday;}//修改生日
intGetBirth(){returnBirthday;}//提取生日
voidSetHomeAdd(string); //修改住址
stringGetHomeAdd(){returnHomeAddress;}
//提取住址
virtualvoidPrintInfo(); //輸出個人信息
};//接口函數(shù):第二十四頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類派生的學(xué)生類:classStudent:publicPerson //定義派生的學(xué)生類{stringNoStudent; //學(xué)號
coursecs[30]; //30門課程與成績public:Student(stringid,stringname,Tsexsex,intbirthday, stringhomeadd,stringnostud);
//注意派生類構(gòu)造函數(shù)聲明方式
Student(); //默認(rèn)派生類構(gòu)造函數(shù)
~Student(); //派生類析構(gòu)函數(shù)
SetCourse(string,int); //課程設(shè)置
intGetCourse(string); //查找成績
voidPrintInfo(); //打印學(xué)生情況};structcourse{stringcoursename;
intgrade;};驗(yàn)證主函數(shù)第二十五頁,共一百一十一頁,編輯于2023年,星期五8.2派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)注意:本例中標(biāo)準(zhǔn)C++字符串string是作為成員對象使用的(聚合),動態(tài)內(nèi)存分配的構(gòu)造和析構(gòu)被封裝起來,使用十分簡單。如使用動態(tài)生成的C風(fēng)格字符串,要考慮深復(fù)制,那要復(fù)雜得多。
提倡完善的類對象封裝,不僅封裝數(shù)據(jù)和對數(shù)據(jù)的操作,而且封裝資源的動態(tài)分配與釋放,形成一個完備的子系統(tǒng)。在一個有層次結(jié)構(gòu)的類體系中資源的動態(tài)分配與釋放應(yīng)封裝在成員對象中,如同使用標(biāo)準(zhǔn)的string字符串類那樣。聚合是一種完善的封裝。采用成員對象將大大簡化層次結(jié)構(gòu)的類體系中資源的動態(tài)分配與釋放的處理方法,不再出現(xiàn)難度極大的多層次的深復(fù)制。第二十六頁,共一百一十一頁,編輯于2023年,星期五8.3多重繼承與派生類成員標(biāo)識(選讀)由多個基類共同派生出新的派生類,這樣的繼承結(jié)構(gòu)被稱為多重繼承或多繼承(multiple-inheritance)
椅子床沙發(fā)(單繼承)躺椅(多重繼承)兩用沙發(fā)(多重繼承)圖8.2椅子,床到兩用沙發(fā)多重繼承實(shí)例:第二十七頁,共一百一十一頁,編輯于2023年,星期五在冊人員學(xué)生(單繼承)教職工(單繼承)兼職教師(單繼承)教師(單繼承)行政人員(單繼承)工人(單繼承)研究生(單繼承)行政人員兼教師(多重繼承)在職研究生(多重繼承)研究生助教(多重繼承)圖8.3大學(xué)在冊人員繼承關(guān)系8.3多重繼承與派生類成員標(biāo)識(選讀)派生出來的新類同樣可以作為基類再繼續(xù)派生出更新的類,依此類推形成一個層次結(jié)構(gòu)。
第二十八頁,共一百一十一頁,編輯于2023年,星期五8.3多重繼承與派生類成員標(biāo)識(選讀)歧義性問題:參見圖8.3,比如行政人員兼教師,在其基類教師中有一個“教職工編號”,另一基類行政人員中也有一個“教職工編號”,如果只講教職工編號那么是哪一個基類中的呢?這兩者可能是一回事,但計算機(jī)系統(tǒng)并不這么認(rèn)為。進(jìn)一步,如果“教職工編號”是由兩個基類“教師”和“行政人員”共同的基類“教職工”類繼承來的,只有同一個標(biāo)識符,也不能用改標(biāo)識符來區(qū)分。
唯一標(biāo)識問題:通常采用作用域分辨符“::”:基類名::成員名;//數(shù)據(jù)成員基類名::成員名(參數(shù)表);//函數(shù)成員
第二十九頁,共一百一十一頁,編輯于2023年,星期五classEGStudent
intNo在職學(xué)號………classGStudentintNo研究生號
……….classStudentintNo學(xué)生號
……….
classPersonintNo身份證號
……….classEmployeeintNo工作證號
……….classPersonintNo身份證號
……….圖8.4(a)在職研究生派生類關(guān)系
定義EGStudent類對象EGStudent1,并假定派生全部為公有派生,而intNo全為公有成員:EGStud1.No//在職學(xué)號EGStud1.GStudent::No//研究生號EGStud1.GStudent.Student::No
//學(xué)生號
EGStud1.GStudent.Student.Person::No//身份證號EGStud1.Employee::No//工作證號EGStud1.Employee.Person::No
//身份證號兩個身份證號從邏輯上講應(yīng)是一回事,但是物理上是分配了不同內(nèi)存空間,是兩個變量,請參見圖8.4(b)。第三十頁,共一百一十一頁,編輯于2023年,星期五Person
Person
StudentEmployeeGStudent
EGStudentPerson成員
Person成員
Student新成員
GStudent新成員
Employee新成員
EGStudent新成員
圖8.4(b)在職研究生派生類存儲圖
建議采用有確定字面意思的標(biāo)識符,它可以被編譯器簡單區(qū)分出來。如果classPerson的身份證號標(biāo)識為intIdPerson,則寫為:EGStud1.GStudent::IdPersonEGStud1.Employee::IdPerson不必標(biāo)出那么多層次的類,但寫EGStud1.IdPerson是錯的。
作用域分辨符不能嵌套使用,如:EGStud1.GStudent::Student::No //學(xué)生號EGStud1.GStudent::Student::Person::No //身份證號是錯誤的。8.3多重繼承與派生類成員標(biāo)識(選讀)第三十一頁,共一百一十一頁,編輯于2023年,星期五8.3多重繼承與派生類成員標(biāo)識(選讀)一般數(shù)據(jù)成員總是私有成員,派生類對基類的訪問只能間接進(jìn)行。訪問身份證號,應(yīng)通過classPerson中的公有成員函數(shù)(接口)GetNo()和SetNo()進(jìn)行:EGStud1.Employee.Person::SetNo(intno);no=EGStud1.Employee.Person::GetNo();注意:第三十二頁,共一百一十一頁,編輯于2023年,星期五【例8.2】由圓和高多重繼承派生出圓錐。因?yàn)楣信缮鷷r,在派生類中不可以直接訪問基類的私有成員,但可以直接訪問基類的保護(hù)成員,當(dāng)需要在派生類中訪問基類的數(shù)據(jù)成員時,可以將它們定義為保護(hù)的,而不是私有的。
本例中類Circle為圓;類Line為高;類Cone為圓錐,由Circle和Line公有派生而來。在Cone類中,Circle和Line類的接口完全不變,可以直接調(diào)用,這就是公有派生的優(yōu)點(diǎn)。在Cone的成員函數(shù)中可直接訪問Circle和Line中的公有成員和保護(hù)成員。
【例8.2】由圓和高多重繼承派生出圓錐檢證主程序:圓類Circle定義高類Line定義圓錐類Cone定義第三十三頁,共一百一十一頁,編輯于2023年,星期五虛基類的引入:在圖8.4中,兩個身份證號顯然是不合理的。可以把classPerson這個共同基類設(shè)置為虛基類,這樣就僅有一個Person基類成員,從不同路徑繼承來的同名數(shù)據(jù)成員(身份證號)在內(nèi)存中就是同一個數(shù)據(jù)。8.4虛基類(選讀)注意:virtual關(guān)鍵字只對緊隨其后的基類名起作用:classStudent:virtual
publicPerson{...};classEmployee:virtual
publicPerson{...};虛基類(virtualbaseclass)定義:class
派生類名:virtual訪問限定符基類類名{...};class
派生類名:訪問限定符
virtual基類類名{...};第三十四頁,共一百一十一頁,編輯于2023年,星期五8.4虛基類(選讀)圖8.5采用虛基類后在職研究生類儲存圖StudentGStudentEGStudentPersonStudent新成員GStudent新成員PersonEmployee新成員Person成員EGStudent新成員PersonPersonEmployee這種繼承稱為虛擬繼承虛擬繼承:在Person的位置上放的是指針,兩個指針都指向Person成員存儲的內(nèi)存。這種繼承稱為虛擬繼承(virtualinheritance)。第三十五頁,共一百一十一頁,編輯于2023年,星期五8.4虛基類(選讀)派生類名::派生類名(參數(shù)總表):基類名1(參數(shù)名表1)《,基類名2(參數(shù)名表2),……,基類名n(參數(shù)名表n)》,《成員對象名1(成員對象參數(shù)名表1),……,成員對象名m(成員對象參數(shù)名表m)》,底層虛基類名1(參數(shù)名表1)《,……,底層虛基類名r(參數(shù)名表r)》{……//派生類新增成員的初始化};//所列出的成員對象名全部為新增成員對象的名字在多層虛擬繼承構(gòu)造函數(shù)中,基類名不僅要列出直接基類,而且要列出底層虛基類,否則編譯器認(rèn)為出錯。虛擬繼承的構(gòu)造函數(shù):第三十六頁,共一百一十一頁,編輯于2023年,星期五8.4虛基類(選讀)在派生類對象的創(chuàng)建中:首先是虛基類的構(gòu)造函數(shù)并按它們聲明的順序構(gòu)造。第二批是非虛基類的構(gòu)造函數(shù)按它們聲明的順序調(diào)用。第三批是成員對象的構(gòu)造函數(shù)。最后是派生類自己的構(gòu)造函數(shù)被調(diào)用。構(gòu)造函數(shù)執(zhí)行次序:第三十七頁,共一百一十一頁,編輯于2023年,星期五8.4虛基類(選讀)【例8.3】在采用虛基類的多重繼承中,構(gòu)造與析構(gòu)的次序。classDclass:publicBclass1,virtualBclass3,virtualBclass2{Objectobject;public:Dclass():object(),Bclass2(),Bclass3(),Bclass1(){cout<<"派生類建立!\n";}~Dclass(){cout<<"派生類析構(gòu)!\n";}};voidmain(){ Dclassdd;cout<<"主程序運(yùn)行!\n";}第三十八頁,共一百一十一頁,編輯于2023年,星期五運(yùn)行結(jié)果:ConstructorBclass3 //第一個虛擬基類,與派生類析構(gòu)函數(shù)排列無關(guān)ConstructorBclass2 //第二個虛擬基類ConstructorBclass1 //非虛擬基類ConstructorObject //對象成員派生類建立!主程序運(yùn)行!派生類析構(gòu)!deconstructorObject //析構(gòu)次序相反deconstructorBclass1deconstructorBclass2deconstructorBclass3//析構(gòu)的次序與構(gòu)造的次序相反。8.4虛基類(選讀)第三十九頁,共一百一十一頁,編輯于2023年,星期五對照圖8.5,盡管Employee和Student的構(gòu)造函數(shù)都包含Person的構(gòu)造函數(shù),但并未真正調(diào)用。唯一的一次調(diào)用是在EGStudent構(gòu)造函數(shù)中。如是非虛基類,則有兩次調(diào)用。8.4虛基類(選讀)【例8.4】虛基類在多層多重繼承中的應(yīng)用
——在職研究生類定義。以虛基類定義公有派生的學(xué)生類以虛基類定義公有派生的研究生類以虛基類定義公有派生的教職工類多重繼承的以虛基類定義公有派生的在職研究生類第四十頁,共一百一十一頁,編輯于2023年,星期五一、派生類與基類:
在任何需要基類對象的地方都可以用公有派生類的對象來代替,這條規(guī)則稱賦值兼容規(guī)則。它包括以下情況:8.5派生類應(yīng)用討論1.
派生類的對象可以賦值給基類的對象,這時是把派生類對象中從對應(yīng)基類中繼承來的成員賦值給基類對象。反過來不行,因?yàn)榕缮惖男鲁蓡T無值可賦。2.
可以將一個派生類的對象的地址賦給其基類的指針變量,但只能通過這個指針訪問派生類中由基類繼承來的成員,不能訪問派生類中的新成員。同樣也不能反過來做。3.
派生類對象可以初始化基類的引用。引用是別名,但這個別名只能包含派生類對象中的由基類繼承來的成員?!纠?.5】為例8.1定義復(fù)制函數(shù),實(shí)現(xiàn)深復(fù)制。第四十一頁,共一百一十一頁,編輯于2023年,星期五二、繼承與聚合
繼承使派生類可以利用基類的成員,如果我們把基類的對象作為一個新類的對象成員,也可以取得類似的效果。派生類采用繼承方法,成員對象是聚合的概念?;愒谂缮愔兄荒芾^承一個(間接基類不在討論之中)不能同時安排兩個,否則成員名即使使用域分辨符也會發(fā)生沖突:classA{public:intK;...};classB:publicA,publicA{...};兩個A無論如何無法分辨出來。如果要用兩個A只能采用成員對象。
更深入地探討后會發(fā)現(xiàn):成員對象體現(xiàn)了封裝更深層次的含義。在派生類和它的基類中是不應(yīng)該有內(nèi)存的動態(tài)分配的,動態(tài)分配的部分應(yīng)該封裝在成員對象中,在該成員對象的析構(gòu)函數(shù)中釋放內(nèi)存,在該成員對象中提供深復(fù)制。類string就是如此。它的內(nèi)部就是一個完備的小系統(tǒng)。這樣程序員就可以放心地使用它,而不需要為它做任何事情。8.5派生類應(yīng)用討論第四十二頁,共一百一十一頁,編輯于2023年,星期五8.6多態(tài)性與虛函數(shù)問題:如何用同一個函數(shù)(同名函數(shù))求三角形、長方形、梯形等不同基本形狀的面積?第四十三頁,共一百一十一頁,編輯于2023年,星期五8.6多態(tài)性與虛函數(shù)多態(tài)性:多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的關(guān)鍵技術(shù)之一。若程序設(shè)計語言不支持多態(tài)性,不能稱為面向?qū)ο蟮恼Z言。利用多態(tài)性技術(shù),可以調(diào)用同一個函數(shù)名的函數(shù),實(shí)現(xiàn)完全不同的功能。在C++中有兩種多態(tài)性
編譯時的多態(tài)性
運(yùn)行時的多態(tài)性
運(yùn)行時的多態(tài)性是指在程序執(zhí)行前,無法根據(jù)函數(shù)名和參數(shù)來確定該調(diào)用哪一個函數(shù),必須在程序執(zhí)行過程中,根據(jù)執(zhí)行的具體情況來動態(tài)地確定。它是通過類繼承關(guān)系和虛函數(shù)來實(shí)現(xiàn)的。目的也是建立一種通用的程序。通用性是程序追求的主要目標(biāo)之一。
通過函數(shù)的重載和運(yùn)算符的重載來實(shí)現(xiàn)的。第四十四頁,共一百一十一頁,編輯于2023年,星期五8.6多態(tài)性與虛函數(shù)8.6.1虛函數(shù)的定義
8.6.4動態(tài)綁定
(選讀)
8.6.2純虛函數(shù)
8.6.3
繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)
第四十五頁,共一百一十一頁,編輯于2023年,星期五8.6.1虛函數(shù)的定義虛函數(shù)的概念:虛函數(shù)是一個類的成員函數(shù),定義格式如下:virtual返回類型函數(shù)名(參數(shù)表);關(guān)鍵字virtual指明該成員函數(shù)為虛函數(shù)。virtual僅用于類定義中,如虛函數(shù)在類外定義,不可再加virtual。當(dāng)一個類的某個成員函數(shù)被定義為虛函數(shù),則由該類派生出來的所有派生類中,該函數(shù)始終保持虛函數(shù)的特征。第四十六頁,共一百一十一頁,編輯于2023年,星期五8.6.1虛函數(shù)的定義當(dāng)在派生類中重新定義虛函數(shù)(overridingavirtualfunction,亦譯作超載或覆蓋)時,不必加關(guān)鍵字virtual。但重新定義時不僅要同名,而且它的參數(shù)表和返回類型全部與基類中的虛函數(shù)一樣,否則出錯。虛函數(shù)與在8.1.1節(jié)中介紹的派生類的第二步——改造類成員,同名覆蓋(override)有關(guān):如未加關(guān)鍵字virtual,則是普通的派生類中的新成員函數(shù)覆蓋基類同名成員函數(shù)(當(dāng)然參數(shù)表必須一樣,否則是重載),可稱為同名覆蓋函數(shù),它不能實(shí)現(xiàn)運(yùn)行時的多態(tài)性。
虛函數(shù)定義要點(diǎn):第四十七頁,共一百一十一頁,編輯于2023年,星期五虛函數(shù)與運(yùn)行時的多態(tài)性:【例8.6】計算學(xué)分??捎杀究粕惻缮鲅芯可?,但它們各自的從課程學(xué)時數(shù)折算為學(xué)分?jǐn)?shù)的算法是不同的,本科生是16個學(xué)時一學(xué)分,而研究生是20個學(xué)時一學(xué)分。8.6.1虛函數(shù)的定義【例8.7】計算學(xué)分。派生類定義不再重復(fù)。第四十八頁,共一百一十一頁,編輯于2023年,星期五成員函數(shù)設(shè)置為虛函數(shù)的要點(diǎn):1.派生類中定義虛函數(shù)必須與基類中的虛函數(shù)同名外,還必須同參數(shù)表,同返回類型。否則被認(rèn)為是重載,而不是虛函數(shù)。如基類中返回基類指針,派生類中返回派生類指針是允許的,這是一個例外。2.只有類的成員函數(shù)才能說明為虛函數(shù)。這是因?yàn)樘摵瘮?shù)僅適用于有繼承關(guān)系的類對象。3.靜態(tài)成員函數(shù),是所有同一類對象共有,不受限于某個對象,不能作為虛函數(shù)。4.實(shí)現(xiàn)動態(tài)多態(tài)性時,必須使用基類類型的指針變量或引用,使該指針指向該基類的不同派生類的對象,并通過該指針指向虛函數(shù),才能實(shí)現(xiàn)動態(tài)的多態(tài)性。8.6.1虛函數(shù)的定義第四十九頁,共一百一十一頁,編輯于2023年,星期五5.內(nèi)聯(lián)函數(shù)因?yàn)槊總€對象有獨(dú)立的一份函數(shù)代碼,無映射關(guān)系,不能作為虛函數(shù)。6.析構(gòu)函數(shù)可定義為虛函數(shù),構(gòu)造函數(shù)不能定義虛函數(shù),因?yàn)樵谡{(diào)用構(gòu)造函數(shù)時對象還沒有完成實(shí)例化。在基類中及其派生類中都動態(tài)分配的內(nèi)存空間時,必須把析構(gòu)函數(shù)定義為虛函數(shù),實(shí)現(xiàn)撤消對象時的多態(tài)性。7.函數(shù)執(zhí)行速度要稍慢一些。為了實(shí)現(xiàn)多態(tài)性,每一個派生類中均要保存相應(yīng)虛函數(shù)的入口地址表,函數(shù)的調(diào)用機(jī)制也是間接實(shí)現(xiàn)。所以多態(tài)性總是要付出一定代價,但通用性是一個更高的目標(biāo)。8.如果定義放在類外,virtual只能加在函數(shù)聲明前面,不能(再)加在函數(shù)定義前面。正確的定義必須不包括virtual。8.6.1虛函數(shù)的定義第五十頁,共一百一十一頁,編輯于2023年,星期五8.6.1虛函數(shù)的定義【例8.5_1】根據(jù)賦值兼容規(guī)則可以用基類的指針指向派生類對象,如果由該指針撤銷派生類對象,則必須將析構(gòu)函數(shù)說明為虛函數(shù),實(shí)現(xiàn)多態(tài)性,自動調(diào)用派生類析構(gòu)函數(shù)。通常要求將類設(shè)計成通用的,無論其他程序員怎樣調(diào)用都必須保證不出錯,所以必須把析構(gòu)函數(shù)定義為虛函數(shù)。下面把【例8.5】析構(gòu)函數(shù)改造為虛函數(shù)classPerson{
//數(shù)據(jù)成員略public:
virtual~Person();
//只需在此聲明一次,派生類的析構(gòu)函數(shù)全為虛函數(shù)
};
//其他成員函數(shù)略Person::~Person(){cout<<"Person析構(gòu)函數(shù)"<<endl;}第五十一頁,共一百一十一頁,編輯于2023年,星期五Person*per4;Student*stu4=newStudent;//動態(tài)建立對象*stu4*stu4=stu1;//把stu1的數(shù)據(jù)拷入*stu4stu4->PrintStudentInfo();per4=stu4;deleteper4;//用基類指針撤銷派生類,動態(tài)生成的對象必須顯式撤銷8.6.1虛函數(shù)的定義在主函數(shù)中添加以下內(nèi)容:
通過在析構(gòu)函數(shù)中加顯示語句發(fā)現(xiàn)先調(diào)Student析構(gòu)函數(shù),后調(diào)Person析構(gòu)函數(shù)。這里再次強(qiáng)調(diào)動態(tài)生成的對象必須顯式撤銷。第五十二頁,共一百一十一頁,編輯于2023年,星期五純虛函數(shù):純虛函數(shù)(purevirtualfunction)是指被標(biāo)明為不具體實(shí)現(xiàn)的虛擬成員函數(shù)。它用于這樣的情況:定義一個基類時,會遇到無法定義基類中虛函數(shù)的具體實(shí)現(xiàn),其實(shí)現(xiàn)依賴于不同的派生類。8.6.2純虛函數(shù)純虛函數(shù)的定義:virtual返回類型函數(shù)名(參數(shù)表)=0;含有純虛函數(shù)的基類是不能用來定義對象的。純虛函數(shù)沒有實(shí)現(xiàn)部分,不能產(chǎn)生對象,所以含有純虛函數(shù)的類是抽象類。第五十三頁,共一百一十一頁,編輯于2023年,星期五1定義純虛函數(shù)時,不能定義虛函數(shù)的實(shí)現(xiàn)部分。即使是函數(shù)體為空也不可以,函數(shù)體為空就可以執(zhí)行,只是什么也不做就返回。而純虛函數(shù)不能調(diào)用。2“=0”表明程序員將不定義該函數(shù),函數(shù)聲明是為派生類保留一個位置?!?0”本質(zhì)上是將指向函數(shù)體的指針定為NULL。3在派生類中必須有重新定義的純虛函數(shù)的函數(shù)體,這樣的派生類才能用來定義對象。8.6.2純虛函數(shù)定義純虛函數(shù)的要點(diǎn):第五十四頁,共一百一十一頁,編輯于2023年,星期五【例8.8】學(xué)校對在冊人員進(jìn)行獎勵,依據(jù)是業(yè)績分,但是業(yè)績分的計算方法只能對具體人員進(jìn)行,如學(xué)生,教師,行政人員,工人,算法都不同,所以可以將在冊人員類作為一個抽象類,業(yè)績計算方法作為一個純虛函數(shù)。在主函數(shù)中全部用指向基類的指針來調(diào)用8.6.2純虛函數(shù)業(yè)績分基類定義業(yè)績分學(xué)生派生類定義業(yè)績分教師派生類定義驗(yàn)證主函數(shù)第五十五頁,共一百一十一頁,編輯于2023年,星期五【例8.9】用虛函數(shù)來實(shí)現(xiàn)辛普生法求函數(shù)的定積分。8.6.2純虛函數(shù)純虛函數(shù)實(shí)現(xiàn)通用算法:辛普生法求定積分類在派生類中加被積函數(shù):驗(yàn)證主函數(shù)第五十六頁,共一百一十一頁,編輯于2023年,星期五8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)【例8.10】通用單鏈表派生類。第一步改造【例7.4】的頭文件,不采用模板類,而采用虛函數(shù)實(shí)現(xiàn)多態(tài)性,達(dá)到通用的目的。結(jié)點(diǎn)類數(shù)據(jù)域被改造為指針,而把數(shù)據(jù)放在一個抽象類中,由指針與之建立聯(lián)系。數(shù)據(jù)域(指向抽象數(shù)據(jù)類的指針)由抽象類派生的數(shù)據(jù)類對象(如串對象)指針域(指向下一結(jié)點(diǎn))結(jié)點(diǎn)類對象動態(tài)建立的數(shù)據(jù)類對象圖8.9結(jié)點(diǎn)構(gòu)造第五十七頁,共一百一十一頁,編輯于2023年,星期五classObject{//數(shù)據(jù)類為抽象類public:Object(){}virtualbooloperator>(Object&)=0;
//純虛函數(shù),參數(shù)必須為引用或指針
virtualbooloperator!=(Object&)=0;
//純虛函數(shù),參數(shù)必須為引用或指針
virtualvoidPrint()=0;//純虛函數(shù)
virtual~Object(){}};//析構(gòu)函數(shù)可為虛函數(shù),構(gòu)造函數(shù)不行8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)結(jié)點(diǎn)組織,采用結(jié)點(diǎn)類加數(shù)據(jù)類數(shù)據(jù)類定義:本題要點(diǎn):采用虛函數(shù)實(shí)現(xiàn)多態(tài)性,達(dá)到通用的目的。堆內(nèi)存的分配與釋放,關(guān)鍵不是創(chuàng)建,而是釋放!第五十八頁,共一百一十一頁,編輯于2023年,星期五說明:數(shù)據(jù)抽象類中含有三個純虛函數(shù):輸出函數(shù)和兩個比較函數(shù)。當(dāng)抽象類在派生時重新定義三個純虛函數(shù),可以進(jìn)行各種類型,包括類和結(jié)構(gòu)對象的比較和輸出。本例介紹程序總體組成為主,鏈表的操作由學(xué)生自己仔細(xì)閱讀。8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)抽象類中的析構(gòu)函數(shù)也是虛函數(shù),這一點(diǎn)非常重要,當(dāng)抽象類派生的數(shù)據(jù)類的數(shù)據(jù)部分是動態(tài)產(chǎn)生的,而由結(jié)點(diǎn)類刪除釋放數(shù)據(jù)類對象時,必須由數(shù)據(jù)類的析構(gòu)函數(shù)來釋放該類對象數(shù)據(jù)部分占用的動態(tài)分配的內(nèi)存。這時必須重新定義析構(gòu)函數(shù)。第五十九頁,共一百一十一頁,編輯于2023年,星期五ClassNode{Object*info;//數(shù)據(jù)域用指針指向數(shù)據(jù)類對象
Node*link;//指針域public:Node();//生成頭結(jié)點(diǎn)的構(gòu)造函數(shù)
~Node();//析構(gòu)函數(shù)
voidInsertAfter(Node*P);//在當(dāng)前結(jié)點(diǎn)后插入一個結(jié)點(diǎn)
Node*RemoveAfter();
//刪除當(dāng)前結(jié)點(diǎn)的后繼結(jié)點(diǎn),返回該結(jié)點(diǎn)備用
voidLinkinfo(Object*obj);//把數(shù)據(jù)對象連接到結(jié)點(diǎn)
friendclassList;
//以List為友元類,List可直接訪問Node的私有函數(shù),};8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)結(jié)點(diǎn)類定義:第六十頁,共一百一十一頁,編輯于2023年,星期五classList{Node*head,*tail;//鏈表頭指針和尾指針public:List();//構(gòu)造函數(shù),生成頭結(jié)點(diǎn)(空鏈表)~List();//析構(gòu)函數(shù)
voidMakeEmpty();//清空鏈表,只余表頭結(jié)點(diǎn)
Node*Find(Object&obj);
//搜索數(shù)據(jù)域與定值相同的結(jié)點(diǎn),返回該結(jié)點(diǎn)的地址
intLength();//計算單鏈表長度
voidPrintList();//打印鏈表的數(shù)據(jù)域
voidInsertFront(Node*p);//可用來向前生成鏈表
voidInsertRear(Node*p);//可用來向后生成鏈表
voidInsertOrder(Node*p);//按升序生成鏈表
Node*CreatNode();//創(chuàng)建一個結(jié)點(diǎn)(孤立結(jié)點(diǎn))Node*DeleteNode(Node*p);};//刪除指定結(jié)點(diǎn)8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)鏈表類定義:第六十一頁,共一百一十一頁,編輯于2023年,星期五第二步,取代模板定義泛型類型為具體類型(包括類)的步驟是由抽象類派生數(shù)據(jù)類。數(shù)據(jù)類的數(shù)據(jù)采用字符類串string,動態(tài)分配和釋放內(nèi)存都在string類中完成。為了完成數(shù)據(jù)類的比較和輸出,超載了比較運(yùn)算符和輸出函數(shù)(虛函數(shù))。數(shù)據(jù)類的比較實(shí)際是字符串string的比較。8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)classStringObject:publicObject{stringsptr;public:StringObject(){sptr="";}StringObject(strings){sptr=s;}~StringObject();//析構(gòu)函數(shù)
booloperator>(Object&);//大于函數(shù)
booloperator!=(Object&);//不等于函數(shù)
voidPrint();//打印函數(shù)};驗(yàn)證主函數(shù)運(yùn)行結(jié)果第六十二頁,共一百一十一頁,編輯于2023年,星期五分析與比較:
在該程序中,特別要仔細(xì)揣摩堆內(nèi)存的分配與釋放。刪除一個結(jié)點(diǎn)時系統(tǒng)自動調(diào)用結(jié)點(diǎn)類析構(gòu)函數(shù)釋放結(jié)點(diǎn)占用的動態(tài)內(nèi)存,而結(jié)點(diǎn)類析構(gòu)函數(shù)自動調(diào)用數(shù)據(jù)域類虛析構(gòu)函數(shù),數(shù)據(jù)域類析構(gòu)函數(shù)自動調(diào)用string類的析構(gòu)函數(shù)釋放所占用的動態(tài)內(nèi)存。一環(huán)套一環(huán),一步都不能錯。這是使用動態(tài)內(nèi)存分配的關(guān)鍵。即關(guān)鍵不是創(chuàng)建,而是釋放!
運(yùn)行時的多態(tài)性需要維護(hù)一個動態(tài)指針表才能正確指向各相關(guān)類中的同名虛函數(shù)。所以多態(tài)與模板比較,模板的效率更高,標(biāo)準(zhǔn)模板庫中用容器來泛型化數(shù)據(jù)結(jié)構(gòu)中的許多算法。對數(shù)據(jù)結(jié)構(gòu)的使用當(dāng)然借助模板庫。多態(tài)不適用于性能要求很高的實(shí)時應(yīng)用程序,但繼承與多態(tài)可用與其它更多方面,每一種技術(shù)都有可以充分發(fā)揮自己能力的地方。8.6.3繼承與多態(tài)的應(yīng)用——單鏈表派生類(選讀)第六十三頁,共一百一十一頁,編輯于2023年,星期五動態(tài)綁定(dynamicbinding)亦稱滯后綁定(latebinding),對應(yīng)于靜態(tài)綁定(staticbinding)。如果使用對象名和點(diǎn)成員選擇運(yùn)算符“.”引用特定的一個對象來調(diào)用虛函數(shù),則被調(diào)用的虛函數(shù)是在編譯時確定的(稱為靜態(tài)綁定)
如果使用基類指針或引用指明派生類對象并使用該指針調(diào)用虛函數(shù)(成員選擇符用箭頭號“->”),則程序動態(tài)地(運(yùn)行時)選擇該派生類的虛函數(shù),稱為動態(tài)綁定。8.6.4動態(tài)綁定(選讀)綁定是指計算機(jī)程序自身彼此關(guān)聯(lián)的過程,是把一個標(biāo)識符名和一個存儲地址聯(lián)系在一起的過程,也就是把一條消息和一個對象的操作相結(jié)合的過程。第六十四頁,共一百一十一頁,編輯于2023年,星期五圖8.9虛函數(shù)調(diào)用的控制流程“dog”StringObject動態(tài)無名對象StringObject動態(tài)無名對象“cat”指向Object類指針指向結(jié)點(diǎn)類指針指向Object類指針指向結(jié)點(diǎn)類指針指向Object類指針Λ指向結(jié)點(diǎn)類指針StringObject動態(tài)無名對象“cock”·
·
·析構(gòu)函數(shù)指針0比較函數(shù)指針0輸出函數(shù)指針StringObject虛函數(shù)表抽象類Object虛函數(shù)表析構(gòu)函數(shù)指針比較函數(shù)指針輸出函數(shù)指針ComplexObject虛函數(shù)
析構(gòu)函數(shù)指針
比較函數(shù)指針
輸出函數(shù)指針·
·
·默認(rèn)析構(gòu)函數(shù)釋放動態(tài)串析構(gòu)函數(shù)串比較函數(shù)打印串函數(shù)默認(rèn)析構(gòu)函數(shù)復(fù)數(shù)模大小比較函數(shù)打印復(fù)數(shù)函數(shù)第六十五頁,共一百一十一頁,編輯于2023年,星期五8.6.4動態(tài)綁定(選讀)
C++編譯器編譯含有一個或幾個虛函數(shù)的類及其派生類時,對該類建立虛函數(shù)表(Virtualfunctiontable,vtable)。虛函數(shù)表使執(zhí)行程序正確選擇每次執(zhí)行時應(yīng)使用的虛函數(shù)。多態(tài)是由復(fù)雜的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,參見圖8.10。圖8.10是以【例8.10】為基礎(chǔ)的,不過增加了一個由抽象類Object派生的復(fù)數(shù)數(shù)據(jù)類ComplexObject。圖中列出了基類和各派生類的虛函數(shù)表,這些表是由指向函數(shù)的指針組成的。
第六十六頁,共一百一十一頁,編輯于2023年,星期五8.6.4動態(tài)綁定(選讀)
還有第二層指針,在實(shí)例化帶虛函數(shù)的類(創(chuàng)建對象)時,編譯器在對象前加上一個指向該類的虛函數(shù)表的指針。 第三層指針是鏈表結(jié)點(diǎn)類對象中指向抽象基類Object的指針(這也可以是引用,但本例是指針)。虛函數(shù)的調(diào)用是這樣進(jìn)行的,考慮虛函數(shù)Compare(),則看含“cat”的結(jié)點(diǎn)。由該結(jié)點(diǎn)的info指針找到含“cat”的無名對象,再由對象前的指針找到StringObject虛函數(shù)表,移動4個字節(jié)(一個指針占4個字節(jié))找到比較函數(shù)指針,進(jìn)入串比較函數(shù)。第六十七頁,共一百一十一頁,編輯于2023年,星期五完第八章繼承與派生謝謝!第六十八頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類Person::Person(stringid,stringname,Tsexsex, intbirthday,stringhomeadd){ IdPerson=id; Name=name; Sex=sex; Birthday=birthday; HomeAddress=homeadd;}//作為一個管理程序,這個構(gòu)造函數(shù)并無必要,因?yàn)閿?shù)據(jù)總是另外輸入的。僅為說明語法存在。分析構(gòu)造函數(shù):第六十九頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類Person::Person(){ IdPerson="#";Name="#";Sex=mid; Birthday=0;HomeAddress="#";}分析默認(rèn)的構(gòu)造函數(shù):分析析構(gòu)函數(shù):Person::~Person(){}//string內(nèi)部動態(tài)數(shù)組的釋放,由string自帶的析構(gòu)函數(shù)完成第七十頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類voidPerson::SetName(stringname){ Name=name;//拷入新姓名}修改名字:voidPerson::SetHomeAdd(stringhomeadd){ HomeAddress=homeadd;}修改住址:第七十一頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類voidPerson::PrintInfo(){
inti; cout<<"身份證號:"<<IdPerson<<'\n'<<"姓名:"<<Name<<'\n'<<"性別:";
if(Sex==man)cout<<"男"<<'\n';
else
if(Sex==woman)cout<<"女"<<'\n';
elsecout<<""<<'\n'; cout<<"出生年月日:"; i=Birthday; cout<<i/10000<<"年"; i=i%10000; cout<<i/100<<"月"<<i%100<<"日"<<'\n‘<<"家庭住址:"<<HomeAddress<<'\n';}輸出個人信息:第七十二頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類Student::Student(stringid,stringname,Tsexsex,intbirthday,stringhomeadd,stringnostud):Person(id,name,sex,birthday,homeadd){ //注意Person參數(shù)表不用類型
NoStudent=nostud;
for(inti=0;i<30;i++) //課程與成績清空
{ cs[i].coursename="#"; cs[i].grade=0; }}派生類構(gòu)造函數(shù):第七十三頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類Student::Student()//基類默認(rèn)的無參數(shù)構(gòu)造函數(shù)不必顯式給出{ inti;
NoStudent="";
for(i=0;i<30;i++)//課程與成績清零,將來由鍵盤輸入
{ cs[i].coursename=""; cs[i].grade=0; }}Student::~Student(){}
//基類析構(gòu)函數(shù)以及成員對象析構(gòu)函數(shù)自動調(diào)用默認(rèn)派生類構(gòu)造函數(shù):派生類析構(gòu)函數(shù):第七十四頁,共一百一十一頁,編輯于2023年,星期五intStudent::SetCourse(stringcoursename,intgrade){
boolb=false;//標(biāo)識新輸入的課程,還是更新成績
inti;
for(i=0;i<30;i++){
if(cs[i].coursename=="#") { //判表是否進(jìn)入未使用部分
cs[i].coursename=coursename; cs[i].grade=grade; b=false;break;}
else
if(cs[i].coursename==coursename){ //是否已有該課程記錄
cs[i].grade=grade;b=true;break;}}
if(i==30)return0;//成績表滿返回0
if(b)return1;//修改成績返回1
elsereturn2;//登記成績返回2}學(xué)生類課程設(shè)置函數(shù):第七十五頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類intStudent::GetCourse(stringcoursename){inti;for(i=0;i<30;i++)
if(cs[i].coursename==coursename)
returncs[i].grade;return-1;}//找到返回成績,未找到返回-1查找學(xué)生課程成績函數(shù):第七十六頁,共一百一十一頁,編輯于2023年,星期五【例8.1】由在冊人員類公有派生學(xué)生類voidStudent::PrintInfo(){ Person::PrintInfo();
inti; cout<<"學(xué)號:"<<NoStudent<<'\n';
for(i=0;i<30;i++)//打印各科成績
if(cs[i].coursename!="#") cout<<cs[i].coursename <<'\t'<<cs[i].grade<<'\n';
else
break; cout<<"--------完--------"<<endl;}打印學(xué)生情況函數(shù):第七十七頁,共一百一十一頁,編輯于2023年,星期五例8.1驗(yàn)證用主函數(shù):intmain(void){
chartemp[30];
inti,k;Personper1("320102820818161","沈俊",man,19820818,"南京四牌樓2號");Personper2;per2.SetName("朱明");per2.SetSex(woman);per2.SetBirth(19780528);per2.SetId("320102780528162");per2.SetHomeAdd("南京市成賢街9號");per1.PrintInfo();per2.PrintInfo();Studentstu1("320102811226161","朱海鵬",man,19811226,"南京市黃浦路1號","06000123");第七十八頁,共一百一十一頁,編輯于2023年,星期五cout<<"請輸入各科成績:"<<'\n';
//完整的程序應(yīng)輸入學(xué)號,查找,再操作
while(1)//輸入各科成績,輸入"end"停止
{cin>>temp;//輸入格式:物理80
if(!strcmp(temp,"end"))break;cin>>k;i=stu1.SetCourse(temp,k);
if(i==0)cout<<"成績列表已滿!"<<'\n';
else
if(i==1)cout<<"修改成績"<<'\n';
elsecout<<"登記成績"<<'\n';}stu1.PrintInfo();while(1){ cout<<"查詢成績"<<'\n'<<"請輸入科目:"<<'\n'; cin>>temp;
if(!strcmp(temp,"end"))break; k=stu1.GetCourse(temp);
if(k==-1)cout<<"未查到"<<'\n';
elsecout<<k<<'\n';}
return0;}第七十九頁,共一百一十一頁,編輯于2023年,星期五【例8.2】由圓和高多重繼承派生出圓錐classCircle{protected:
floatx,y,r;//(x,y)為圓心,r為半徑public:Circle(floata=0,floatb=0,floatR=0){x=a;y=b;r=R;}
voidSetcoordinate(floata,floatb){x=a;y=b;}
//設(shè)置圓心坐標(biāo)
voidGetcoordinate(float&a,float
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- Module 5 詞組和關(guān)鍵句型(教學(xué)設(shè)計)-2023-2024學(xué)年外研版英語八年級下冊
- Unit 2 Hobbies Further Study 教學(xué)設(shè)計 -2024-2025學(xué)年譯林版(2024)七年級英語上冊
- 第五課 錦上添花-動作補(bǔ)間動畫 教學(xué)設(shè)計 -2023-2024學(xué)年大連版(2015)初中信息技術(shù)八年級下冊
- 人教版七年級歷史與社會上冊2.3世界大家庭-人口與人種教學(xué)設(shè)計
- 2025年湖南石油化工職業(yè)技術(shù)學(xué)院單招職業(yè)技能測試題庫附答案
- 2025年廣東機(jī)電職業(yè)技術(shù)學(xué)院單招職業(yè)傾向性測試題庫1套
- Unit 7 Happy Birthday!Period I Section A 1a-Pronunciation 教學(xué)設(shè)計 2024-2025學(xué)年人教版英語七年級上冊
- 2025高考生物備考教學(xué)設(shè)計:神經(jīng)調(diào)節(jié)與體液調(diào)節(jié)的關(guān)系教學(xué)設(shè)計
- 第五章 第2節(jié)《城鎮(zhèn)與鄉(xiāng)村》 教學(xué)設(shè)計 - 2024-2025學(xué)年人教(2024)七年級地理上冊
- 2024中國石油工程建設(shè)有限公司西南分公司招聘筆試參考題庫附帶答案詳解
- 醫(yī)院DRG付費(fèi)知識培訓(xùn)課件
- 高考語文一輪復(fù)習(xí):文學(xué)類文本閱讀練習(xí)
- (2024年)保安培訓(xùn)圖文課件
- 中醫(yī)養(yǎng)生保健素養(yǎng)知識講座
- 雷達(dá)干擾技術(shù)概述
- JBT 7901-2023 金屬材料實(shí)驗(yàn)室均勻腐蝕全浸試驗(yàn)方法 (正式版)
- 2024年南通建筑電工證考試題模擬試題電工培訓(xùn)試題及答案(全國通用)
- 2025小學(xué)道德與法治開學(xué)第一課(思想政治理論教育課)
- 基于STM32Cube的嵌入式系統(tǒng)應(yīng)用 教案
- 動畫分鏡頭腳本設(shè)計課件
- 江蘇省成人高等教育畢業(yè)生登記表
評論
0/150
提交評論