C++實(shí)用教程鄭阿奇主編12_第1頁(yè)
C++實(shí)用教程鄭阿奇主編12_第2頁(yè)
C++實(shí)用教程鄭阿奇主編12_第3頁(yè)
C++實(shí)用教程鄭阿奇主編12_第4頁(yè)
C++實(shí)用教程鄭阿奇主編12_第5頁(yè)
已閱讀5頁(yè),還剩50頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第12章繼承和派生1精選課件12.1繼承和派生概述12.1.1繼承的概念1.繼承和概括繼承(Inheritance),是指一個(gè)事物可以繼承其父輩全部或部分特性,同時(shí)本身還有自己的特性。2.類繼承相關(guān)概念在C++中,當(dāng)一個(gè)新類從一個(gè)已定義的類中派生后,新類不僅繼承了原有類的屬性和方法,并且還擁有自己新的屬性和方法,稱為類的繼承和派生。被繼承的類稱為基類(Baseclass)或超類(Superclass)(又稱父類),在基類或父類上建立的新類稱為派生類(Derivedclass)或子類(Subclass)。2精選課件3.類層次關(guān)系的描述方法

上述父類和子類的關(guān)系稱為類層次或繼承關(guān)系。在類設(shè)計(jì)時(shí),常常將這些關(guān)系用樹(shù)來(lái)描述。例如,下圖就是用樹(shù)來(lái)描述學(xué)校人員類的層次關(guān)系。3精選課件12.1.2繼承的特性在C++中,類的繼承具有下列特性:(1)單向性。(2)傳遞性。(3)可重用性。12.1.3派生類的定義在C++中,一個(gè)派生類的定義可按下列格式:

class<派生類名>:[<繼承方式1>]<基類名1>,[<繼承方式2>]<基類名2>,…{ [<派生類的成員>]};

4精選課件12.2繼承方式

C++繼承方式有三種:public(公有)、private(私有)及protected(保護(hù))12.2.1公有繼承公有繼承(public)方式具有下列特點(diǎn):(1)在派生類中,基類的公有成員、保護(hù)成員和私有成員的訪問(wèn)屬性保持不變。(2)派生類對(duì)象只能訪問(wèn)派生類和基類的公有(public)成員。5精選課件[例Ex_PublicDerived]派生類的公有繼承示例。#include<iostream>#include<cstring>usingnamespacestd;classCPerson{public: CPerson(char*name,intage,charsex='M') { strncpy(this->name,name,20); this->age=age; this->sex=sex; } voidSetNameAndSex(char*name,charsex='M') //更改姓名和性別 { strncpy(this->name,name,20); this->sex=sex; }protected:6精選課件 voidSetAge(intage) { this->age=age; } voidShowInfo() //顯示信息 { cout<<"姓名:"<<name<<endl; cout<<"性別:"<<(sex=='M'?"男":"女")<<endl; cout<<"年齡:"<<age<<endl; }private: char name[20]; //姓名 char sex; //性別 int age; //年齡};classCStudent:publicCPerson7精選課件{public: CStudent(char*name,char*no,intage,charsex='M') :CPerson(name,age,sex) //調(diào)用基類構(gòu)造函數(shù)進(jìn)行初始化 { strncpy(this->stuno,no,20); } voidSetScore(floats1,floats2,floats3) { score[0]=s1; score[1]=s2; score[2]=s3; total=s1+s2+s3; ave=total/(float)3.0; } voidSetNoAndAge(char*no,intage) { strncpy(this->stuno,no,20); this->SetAge(age); } voidShowAll() { ShowInfo(); //調(diào)用基類的成員函數(shù) cout<<"學(xué)號(hào):"<<stuno<<endl; cout<<"三門成績(jī):"<<score[0]<<"\t"<<score[1]<<"\t"<<score[2]<<endl; cout<<"總成績(jī)和平均分:"<<total<<"\t"<<ave<<endl; }8精選課件private: char stuno[20]; //學(xué)號(hào) float score[3],ave,total; //三門成績(jī)、平均分和總分};intmain(){ CStudentone("LiMing","21050101",19); //A one.SetScore(90,80,84); //B one.ShowAll(); //調(diào)用派生類的公有成員函數(shù) one.SetNameAndSex("WangFang",'W'); //調(diào)用基類的公有成員函數(shù) one.SetNoAndAge("21050102",18); //調(diào)用派生類的公有成員函數(shù) one.ShowAll(); //調(diào)用派生類的公有成員函數(shù) return0;}9精選課件程序運(yùn)行結(jié)果如下:10精選課件12.2.2私有繼承私有繼承(private)方式具有下列特點(diǎn):(1)在派生類中,基類的公有成員、保護(hù)成員和私有成員的訪問(wèn)屬性都將變成私有(private),且基類的私有成員在派生類中被隱藏。(2)由于基類的所有成員在派生類中都變成私有的,因此基類的所有成員在派生類的子類中都是不可見(jiàn)的。(3)派生類對(duì)象只能訪問(wèn)派生類的公有成員,不能訪問(wèn)基類的任何成員。11精選課件[例Ex_PrivateDerived]派生類的私有繼承示例。#include<iostream>#include<cstring>usingnamespacestd;classCPerson{public: CPerson(char*name,intage,charsex='M') { strncpy(this->name,name,20); this->age=age; this->sex=sex; } voidSetNameAndSex(char*name,charsex='M')//更改姓名和性別 { strncpy(this->name,name,20); this->sex=sex; }protected:12精選課件 voidSetAge(intage) { this->age=age; } voidShowInfo() //顯示信息 { cout<<"姓名:"<<name<<endl; cout<<"性別:"<<(sex=='M'?"男":"女")<<endl; cout<<"年齡:"<<age<<endl; }private: char name[20]; //姓名 char sex; //性別 int age; //年齡};classCStudent:privateCPerson{public: CStudent(char*name,char*no,intage,charsex='M') :CPerson(name,age,sex) //調(diào)用基類公有構(gòu)造函數(shù)進(jìn)行初始化 13精選課件{ strncpy(this->stuno,no,20); }public: voidSetScore(floats1,floats2,floats3) { score[0]=s1; score[1]=s2; score[2]=s3; total=s1+s2+s3; ave=total/(float)3.0; } voidSetNoAndAge(char*no,intage) { strncpy(this->stuno,no,20); this->SetAge(age); } voidShowAll() { ShowInfo(); //調(diào)用基類的保護(hù)成員函數(shù) cout<<"學(xué)號(hào):"<<stuno<<endl; cout<<"三門成績(jī):"<<score[0]<<"\t"<<score[1]<<"\t"<<score[2]<<endl; cout<<"總成績(jī)和平均分:"<<total<<"\t"<<ave<<endl; } //修改的代碼14精選課件 voidSetNameAndSex(char*name,charsex='M') //更改姓名和性別 {

CPerson::SetNameAndSex(name,sex); //調(diào)用基類的公有成員函數(shù) } private: char stuno[20]; //學(xué)號(hào) float score[3],ave,total;//三門成績(jī)、平均分和總分};intmain(){ CStudentone("LiMing","21050101",19); one.SetScore(90,80,84); one.ShowAll(); one.SetNameAndSex("WangFang",'W'); one.SetNoAndAge("21050102",18); one.ShowAll(); return0;}程序運(yùn)行結(jié)果同前。15精選課件12.2.3保護(hù)繼承保護(hù)繼承(protected)方式具有下列特點(diǎn):(1)在派生類中,基類的公有成員、保護(hù)成員的訪問(wèn)屬性都將變成保護(hù)的。(2)同私有繼承一樣,在保護(hù)繼承方式下,派生類中仍可訪問(wèn)基類的公有成員和保護(hù)成員。16精選課件12.3派生類的構(gòu)造和析構(gòu)12.3.1構(gòu)造和析構(gòu)次1.單繼承如圖12.2(a)所示,A類是B類的基類,B類又是C類的基類,它們是多層單繼承方式其代碼如下:17精選課件classA{public: A() { cout<<"執(zhí)行A的構(gòu)造函數(shù)"<<endl; } ~A() { cout<<"執(zhí)行A的析構(gòu)函數(shù)"<<endl; }};classB:publicA{public: B() { cout<<"執(zhí)行B的構(gòu)造函數(shù)"<<endl; } ~B() { cout<<"執(zhí)行B的析構(gòu)函數(shù)"<<endl; }};classC:publicB18精選課件{public: C() { cout<<"執(zhí)行C的構(gòu)造函數(shù)"<<endl; } ~C() { cout<<"執(zhí)行C的析構(gòu)函數(shù)"<<endl; }};intmain(){ Cc; return0;}程序運(yùn)行結(jié)果如下19精選課件2.多繼承

如圖12.2(b)所示,類A和類B是C類的基類,它們是多繼承方式,其代碼如下:classA{public: A() { cout<<"執(zhí)行A的構(gòu)造函數(shù)"<<endl; } ~A() { cout<<"執(zhí)行A的析構(gòu)函數(shù)"<<endl; }};classB{public: B() { cout<<"執(zhí)行B的構(gòu)造函數(shù)"<<endl; } ~B() { cout<<"執(zhí)行B的析構(gòu)函數(shù)"<<endl; }};classC:publicB,publicA

20精選課件{public: C() { cout<<"執(zhí)行C的構(gòu)造函數(shù)"<<endl; } ~C() { cout<<"執(zhí)行C的析構(gòu)函數(shù)"<<endl; }};intmain(){ Cc; return0;}程序運(yùn)行結(jié)果如下:執(zhí)行B的構(gòu)造函數(shù)執(zhí)行A的構(gòu)造函數(shù)執(zhí)行C的構(gòu)造函數(shù)執(zhí)行C的構(gòu)造函數(shù)執(zhí)行A的構(gòu)造函數(shù)執(zhí)行B的構(gòu)造函數(shù)21精選課件12.3.2派生類數(shù)據(jù)成員初始化一個(gè)派生類的構(gòu)造函數(shù)的定義可有下列格式:<派生類名>(形參表):基類1(參數(shù)表),基類2(參數(shù)表),…,基類n(參數(shù)表),對(duì)象成員1(參數(shù)表),對(duì)象成員2(參數(shù)表),…,對(duì)象成員n(參數(shù)表){}成員初始化列表例如,一個(gè)長(zhǎng)方體類CCuboid,它從基類矩形類CRect派生而來(lái)。

基類CRect的數(shù)據(jù)成員是兩個(gè)CPoint類對(duì)象ptLT和ptRB,分別表示矩形的左上角點(diǎn)和右下角點(diǎn)的位置。派生類CCuboid自身的數(shù)據(jù)成員有表示高度的fHeight,表示底面中點(diǎn)位置的CPoint對(duì)象ptCenter,如右圖所示。具體程序如下。22精選課件[例Ex_ClassDerived]派生類的構(gòu)造和析構(gòu)示例。#include<iostream>usingnamespacestd;classCPoint{public: CPoint(intx=0,inty=0) //C { xPos=x; yPos=y; cout<<"CPoint構(gòu)造函數(shù)"<<endl; } voidShowPos(boolisEnd=false) { cout<<"pos("<<xPos<<","<<yPos<<")"; if(isEnd) cout<<endl; }private: intxPos,yPos;};23精選課件classCRect{public: CRect(intx1=0,inty1=0,intx2=0,inty2=0) //B :ptLT(x1,y1),ptRB(x2,y2) { cout<<"CRect構(gòu)造函數(shù)"<<endl; } voidShowPos() { ptLT.ShowPos(); cout<<","; ptRB.ShowPos(true); }private: CPointptLT,ptRB;};24精選課件classCCuboid:publicCRect{public: CCuboid(intx1,inty1,intx2,inty2,intheight) //A :CRect(x1,y1,x2,y2), ptCenter((x1+x2)/2,(y1+y2)/2), fHeight(height) { cout<<"CCuboid構(gòu)造函數(shù)"<<endl; } voidShowAll() { cout<<"矩形的角點(diǎn)為:"; CRect::ShowPos(); cout<<"底面矩形的中點(diǎn)為:"; ptCenter.ShowPos(true); cout<<"高為:"<<fHeight<<endl; }25精選課件private: CPoint ptCenter; float fHeight;};intmain(){ CCuboidone(5,5,30,30,50); one.ShowAll(); return0;}程序運(yùn)行結(jié)果如下:26精選課件12.4二義性和虛基類

12.4.1二義性概述一般來(lái)說(shuō),在派生類中對(duì)基類成員的訪問(wèn)應(yīng)該是唯一的。但是多繼承或多層繼承可能造成對(duì)基類中某成員的訪問(wèn)出現(xiàn)不唯一的情況,這種情況稱為基類成員調(diào)用的二義性。二義性出現(xiàn)的情況可以有下列兩種。1.同名成員來(lái)源于不同的基類[例Ex_Conflict1]同名成員來(lái)源于不同的基類27精選課件#include<iostream>usingnamespacestd;classA {public:intx; A(inta=0){x=a;}};classB {public: intx; B(inta=0,intb=0) {x=a;}};classC:publicB,publicA28精選課件{public: intz; C(inta,intb,intc) :A(a),B(b) { z=c; } voidprint() { cout<<"x="<<x<<endl; //編譯出錯(cuò)的地方 cout<<"z="<<z<<endl; }};intmain(){ Cc1(100,200,300); c1.print(); return0;}29精選課件程序中,派生類C同時(shí)繼承了A和B這兩個(gè)基類,由于基類A和基類B都有數(shù)據(jù)成員x,當(dāng)編譯到“cout<<"x="<<x<<endl;”語(yǔ)句時(shí),無(wú)法確定成員x是來(lái)自基類A還是來(lái)自基類B,因此產(chǎn)生了二義性,從而出現(xiàn)編譯錯(cuò)誤。

解決這個(gè)問(wèn)題的簡(jiǎn)單方法是使用域作用運(yùn)算符“

::”來(lái)消除二義性,即將print函數(shù)實(shí)現(xiàn)代碼改為:voidprint(){ cout<<"A::x="<<A::x<<endl; cout<<"B::x="<<B::x<<endl; cout<<"z="<<z<<endl;}重新運(yùn)行的結(jié)果如下30精選課件2.同名成員來(lái)源于同一個(gè)基類[例Ex_Conflict2]同名成員來(lái)源于同一個(gè)基類。#include<iostream>usingnamespacestd;classA{public:intx; A(inta=0){x=a;}};classB1:publicA{public: inty1; B1(inta=0,intb=0) :A(b) { y1=a; }};31精選課件classB2:publicA{public: inty2; B2(inta=0,intb=0) :A(b) { y2=a; }};classC:publicB1,publicB2{public: intz; C(inta,intb,intd,inte,intm) :B1(a,b),B2(d,e) { z=m; }32精選課件voidprint() { cout<<"x="<<x<<endl; //編譯出錯(cuò)的地方 cout<<"y1="<<y1<<",y2="<<y2<<endl; cout<<"z="<<z<<endl; }};intmain(){ Cc1(100,200,300,400,500); c1.print(); return0;}程序中,B1類和B2類都是從基類A繼承的派生類,這時(shí)在繼承B1和B2的派生類C中就有兩個(gè)基類A的拷貝。當(dāng)編譯器編譯到“cout<<"x="<<x<<endl;”語(yǔ)句時(shí),因無(wú)法確定成員x是從類B1中繼承來(lái)的,還是從類B2繼承來(lái)的,因此產(chǎn)生二義性,從而出現(xiàn)了編譯錯(cuò)誤。解決這個(gè)問(wèn)題仍可使用前面的方法,即使用域作用運(yùn)算符“

::”通過(guò)指定基類來(lái)消除二義性。例如,可將print函數(shù)實(shí)現(xiàn)代碼改寫(xiě)為33精選課件voidprint(){ cout<<"B1::x="<<B1::x<<endl; cout<<"B2::x="<<B2::x<<endl; cout<<"y1="<<y1<<",y2="<<y2<<endl; cout<<"z="<<z<<endl;}重新運(yùn)行后的結(jié)果如下:34精選課件12.4.2二義性解決方法(1)當(dāng)派生類和其基類中都有一個(gè)成員X時(shí),在派生類中訪問(wèn)的X就是派生類的成員X,這是C++中類的局部?jī)?yōu)先原則。(2)若A類是B類的基類,B類是C類的基類,當(dāng)A類和B類都有一個(gè)成員X時(shí),則在子類C中訪問(wèn)的X是B類的成員,這是C++中類的最近優(yōu)先原則。對(duì)于出現(xiàn)二義性的第1種情況,指定作用域是最好的解決方法。但對(duì)于第2種情況,指定作用域雖是一種解決方法,但不是最好的辦法。因?yàn)樵谂缮怌中總有兩個(gè)基類A的拷貝,不僅多占用內(nèi)存,而且效率也不高。為此在實(shí)際應(yīng)用中多采用虛基類的形式來(lái)解決。35精選課件12.4.3虛基類和虛繼承1.虛基類的定義虛基類不是指基類是虛的,而是指在派生類中指定的基類是虛繼承方式,即使用下列格式定義派生類的繼承方式:class<派生類名>:virtual[<繼承方式>]<基類名>{ [<派生類的成員>] };[例Ex_VirtualBase]虛基類的使用示例。36精選課件#include<iostream>usingnamespacestd;classA{public:intx; A(inta=0){x=a;}};classB1:virtualpublicA //聲明虛繼承{public: inty1; B1(inta=0,intb=0) :A(b) { y1=a; } voidprint(void) { cout<<"B1:x="<<x<<",y1="<<y1<<endl; }};37精選課件classB2:virtualpublicA //聲明虛繼承{public: inty2; B2(inta=0,intb=0) :A(b) { y2=a; } voidprint(void) { cout<<"B2:x="<<x<<",y2="<<y2<<endl; }};classC:publicB1,publicB2{public: intz; C(inta,intb,intd,inte,intm) :B1(a,b),B2(d,e) { z=m; }38精選課件 voidprint() { B1::print(); B2::print(); cout<<"z="<<z<<endl; }};intmain(){ Cc1(100,200,300,400,500); c1.print(); c1.x=400; c1.print(); return0;}程序運(yùn)行結(jié)果如下:39精選課件2.虛基類的實(shí)質(zhì)在上述示例中,類A、B1、B2和C的層次關(guān)系可用圖12.5來(lái)表示圖12.5類的層次關(guān)系40精選課件12.5兼容兼容是指在公有派生情況下,一個(gè)派生類對(duì)象可以賦給基類對(duì)象,這種情況又稱為賦值兼容,或稱類型自動(dòng)轉(zhuǎn)換。12.5.1賦值兼容規(guī)則簡(jiǎn)單地講,對(duì)于公有派生類來(lái)說(shuō),可以將派生類的對(duì)象直接賦給其基類對(duì)象,反之卻不可以。

12.5.2賦值兼容機(jī)理[例Ex_CastTest]派生類賦值兼容測(cè)試示例。

41精選課件#include<iostream>#include<cstring>usingnamespacestd;classCA{public: CA(intx=0) {a=x;} intgetA() {returna;}private: inta;};classCB{public: CB(intx=0) {b=x;} intgetB() {returnb;}private: intb;};classCC:publicCB,publicCA42精選課件{public: CC(inty=0) {c=y;} intgetC() {returnc;}private: intc;};intmain(){ CC*c=newCC(5); cout<<c->getC()<<","<<c->getB()<<","<<c->getA()<<endl; CAa(3); CBb(4); memcpy((CA*)c,&a,sizeof(a)); //A memcpy((CB*)c,&b,sizeof(b));//B cout<<c->getC()<<","<<c->getB()<<","<<c->getA()<<endl; deletec; return0;}程序運(yùn)行結(jié)果如下:43精選課件

[Ex_CastOther]派生類賦值兼容其他情況示例。#include<iostream>#include<cstring>usingnamespacestd;classCA{public: CA(intx=0) {a=x;} intgetA() {returna;} voidShowAddr() { cout<<"CA對(duì)象的地址:"<<(unsigned)this<<endl; cout<<"\ta的地址:"<<(unsigned)&a<<endl; }private: inta;};classCB{44精選課件public: CB(intx=0) {b=x;} intgetB() {returnb;} voidShowAddr() { cout<<"CB對(duì)象的地址:"<<(unsigned)this<<endl; cout<<"\tb的地址:"<<(unsigned)&b<<endl; }private: intb;};classCC:publicCB,publicCA{public: CC(inty=0) { c=y;} intgetC() {returnc;} voidShowAddr() { CA::ShowAddr(); CB::ShowAddr(); cout<<"CC對(duì)象的地址:"<<(unsigned)this<<endl; cout<<"\tc的地址:"<<(unsigned)&c<<endl; }45精選課件private: intc;};intmain(){ CCc(5); //c對(duì)象中的數(shù)據(jù)成員c為5 cout<<"--------------CCc(5);--------------"<<endl; c.ShowAddr(); cout<<"------------CA*a=&c;-------------"<<endl; CA*a=&c; //A a->ShowAddr(); cout<<"------------CB&b=c;-------------"<<endl; CB&b=c; //B b.ShowAddr(); b=CB(4); *a=CA(3); cout<<c.getC()<<","<<c.getB()<<","<<c.getA()<<endl; return0;}46精選課件程序運(yùn)行結(jié)果如下:47精選課件12.6綜合應(yīng)用實(shí)例12.6.1類間關(guān)系1.繼承關(guān)系2.組合關(guān)系3.共享關(guān)系48精選課件12.6.2設(shè)計(jì)實(shí)例[例Ex_Multi12]綜合應(yīng)用實(shí)例

#include<iostream>#include<cstring>usingnamespacestd;classCPerson{public: CPerson(){} CPerson(char*name,intage,charsex='M') { strncpy(this->name,name,20); this->age=age; this->sex=sex; }49精選課件 voidShowInfo() //顯示信息 { cout<<"姓名:"<<name<<endl; cout<<"性別:"<<(sex=='M'?"男":"女")<<endl; cout<<"年齡:"<<age<<endl; }private: char name[20]; //姓名 char sex; //性別 int age; //年齡};classCStudent:virtualpublicCPerson{public: CStudent(char*name,intage,charsex='M') :CPerson(name,age,sex) //調(diào)用基類構(gòu)造函數(shù)進(jìn)行初始化 {}50精選課件 voidSetData(char*strname,char*stuno,floats1,floats2,floats3) { strncpy(this->classname,strname,20); strncpy(this->stuno,stuno,20); score[0]=s1; score[1]=s2; score[2]=s3; total=s1+s2+s3; ave=total/(float)3.0; } voidShowInfo() { cout<<"班級(jí):"<<classname<<endl; cout<<"學(xué)號(hào):"<<stuno<<endl; cout<<"三門成績(jī):"<<score[0]<<"\t"<<score[1]<<"\t"<<score[2]<<endl; cout<<"總成績(jī)和平均分:"<<total<<"\t"<<av

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論