第12章 類的其它特性_第1頁
第12章 類的其它特性_第2頁
第12章 類的其它特性_第3頁
第12章 類的其它特性_第4頁
第12章 類的其它特性_第5頁
已閱讀5頁,還剩67頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第12章類的其它特性友元函數(shù)類中私有和保護的成員在類外不能被訪問。友元函數(shù)是一種定義在類外部的普通函數(shù),其特點是能夠訪問類中私有成員和保護成員,即類的訪問權(quán)限的限制對其不起作用。友元函數(shù)需要在類體內(nèi)進(jìn)行說明,在前面加上關(guān)鍵字friend。一般格式為:friend<type>FuncName(<args>);friendfloatVolume(A&a);關(guān)鍵字返回值類型函數(shù)名函數(shù)參數(shù)友元函數(shù)不是成員函數(shù),用法也與普通的函數(shù)完全一致,只不過它能訪問類中所有的數(shù)據(jù)。友元函數(shù)破壞了類的封裝性和隱蔽性,使得非成員函數(shù)可以訪問類的私有成員。一個類的友元可以自由地用該類中的所有成員。classA{ floatx,y;public:A(floata,floatb){x=a;y=b;}floatSum(){returnx+y;}

friendfloatSum(A&a){returna.x+a.y; }};voidmain(void){At1(4,5),t2(10,20);

cout<<t1.Sum()<<endl;

cout<<Sum(t2)<<endl;}友元函數(shù)成員函數(shù)友元函數(shù)的調(diào)用,直接調(diào)用成員函數(shù)的調(diào)用,利用對象名調(diào)用友元函數(shù)只能用對象名引用類中的數(shù)據(jù)。私有數(shù)據(jù)有關(guān)友元函數(shù)的使用,說明如下:友元函數(shù)不是類的成員函數(shù)友元函數(shù)近似于普通的函數(shù),它不帶有this指針,因此必須將對象名或?qū)ο蟮囊米鳛橛言瘮?shù)的參數(shù),這樣才能訪問到對象的成員。友元函數(shù)與一般函數(shù)的不同點在于:友元函數(shù)必須在類的定義中說明,其函數(shù)體可在類內(nèi)定義,也可在類外定義;它可以訪問該類中的所有成員(公有的、私有的和保護的),而一般函數(shù)只能訪問類中的公有成員。classA{ floatx,y;public:A(floata,floatb){x=a;y=b;}floatGetx(){returnx;}floatGety(){returny;}floatSum(){returnx+y;}

friendfloatSum(A&);};floatSumxy(A&a){returna.Getx()+a.Gety();}floatSum(A&a){returna.x+a.y;}voidmain(void){At1(1,2),t2(10,20),t3(100,200);

cout<<t1.Sum()<<endl;

cout<<Sum(t2)<<endl;

cout<<Sumxy(t3)<<endl;}成員函數(shù)友元函數(shù),可以直接調(diào)用類中私有成員普通函數(shù),必須通過公有函數(shù)訪問私有成員對象調(diào)用成員函數(shù)調(diào)用友元函數(shù)調(diào)用一般函數(shù)友元函數(shù)友元函數(shù)不受類中訪問權(quán)限關(guān)鍵字的限制,可以把它放在類的私有部分,放在類的公有部分或放在類的保護部分,其作用都是一樣的。換言之,在類中對友元函數(shù)指定訪問權(quán)限是不起作用的。友元函數(shù)的作用域與一般函數(shù)的作用域相同。謹(jǐn)慎使用友元函數(shù)通常使用友元函數(shù)來取對象中的數(shù)據(jù)成員值,而不修改對象中的成員值,則肯定是安全的。大多數(shù)情況是友元函數(shù)是某個類的成員函數(shù),即A類中的某個成員函數(shù)是B類中的友元函數(shù),這個成員函數(shù)可以直接訪問B類中的私有數(shù)據(jù)。這就實現(xiàn)了類與類之間的溝通。注意:一個類的成員函數(shù)作為另一個類的友元函數(shù)時,應(yīng)先定義友元函數(shù)所在的類。classA{...voidfun(B&);};classB{...friendvoidfun(B&);};既是類A的成員函數(shù)又是類B的友元函數(shù)classB; //先定義類A,則首先對類B作引用性說明classA{...... //類A的成員定義

public:voidfun(B&);//函數(shù)的原型說明

};classB{ ......friendvoidA::fun(B&);//定義友元函數(shù)};

voidA::fun(B&b) //函數(shù)的完整定義{...... //函數(shù)體的定義}類A中的成員函數(shù)fun()是類B的友元函數(shù)。即在fun()中可以直接引用類B的私有成員。classB; //必須在此進(jìn)行引用性說明,classA{ floatx,y;public:A(floata,floatb){x=a;y=b;}

floatSum(B&);//說明友元函數(shù)的函數(shù)原型,是類A的一成員函數(shù)};classB{ floatm,n;public:B(floata,floatb){m=a;n=b;}

friendfloatA::Sum(B&);//說明類A的成員函數(shù)是類B的友元函數(shù)}floatA::Sum(B&b) //定義該友元函數(shù){x=b.m+b.n;y=b.m-b.n;}voidmain(void){Aa1(3,5);Bb1(10,20);

a1.Sum(b1); //調(diào)用該函數(shù),因是類A的成員函數(shù),故用類A的對象調(diào)用}a1.x=30a1.y=-10直接引用類B的私有成員類A中有一個函數(shù)可以直接引用類B的私有成員友元類classA{.....friendclassB;}classB{.....}類B是類A的友元類B可以自由使用類A中的成員對于類B而言,類A是透明的類B必須通過類A的對象使用類A的成員constfloatPI=3.1415926;classA{ floatr; floath;public: A(floata,floatb){r=a;h=b;} floatGetr(){returnr;} floatGeth(){returnh;}

friendclassB;//定義類B為類A的友元};classB{intnumber;public: B(intn=1) {number=n;} voidShow(A&a) {cout<<PI*a.r*a.r*a.h*number<<endl;}//求類A的某個對象*n的體積};voidmain(void){ Aa1(25,40),a2(10,40); Bb1(2); b1.Show(a1); b1.Show(a2);}直接引用類A的私有成員類B中的任何函數(shù)都能使用類A中的所有私有成員。不管是按哪一種方式派生,基類的私有成員在派生類中都是不可見的。如果在一個派生類中要訪問基類中的私有成員,可以將這個派生類聲明為基類的友元。classBase{friendclassDerive;.....}classDerive{.....}直接使用Base中的私有成員#include<iostream.h>classM{friendclassN;//N為M的友元,可以直接使用M中的私有成員private:inti,j;voidshow(void){cout<<"i="<<i<<'\t'<<"j="<<j<<'\t';}public:M(inta=0,intb=0){i=a;j=b;}};classN:publicM{//N為M的派生類public:N(inta=0,intb=0):M(a,b){}voidPrint(void){show();cout<<"i+j="<<i+j<<endl; }};voidmain(void){Nn1(10,20);Mm1(100,200);//m1.show(); //私有成員函數(shù),在類外不可調(diào)用

n1.Print();}直接引用類M的私有成員函數(shù)和私有成員基類對象M派生類對象Nx(私有)Show()(私有)x(私私有)Show()(私私有)y(公有)Showy()(公有)showy(){show();cout<<i<<endl;}當(dāng)派生類是基類的友元時,上式可以調(diào)用Nn;n.showy();n.show();錯誤,類外不可調(diào)用虛函數(shù)多態(tài)性:調(diào)用同一個函數(shù)名,可以根據(jù)需要但實現(xiàn)不同的功能。多態(tài)性是面向?qū)ο蟮某绦蛟O(shè)計的關(guān)鍵技術(shù)。編譯時的多態(tài)性(函數(shù)重載)運行時的多態(tài)性(虛函數(shù))多態(tài)性運行時的多態(tài)性是指在程序執(zhí)行之前,根據(jù)函數(shù)名和參數(shù)無法確定應(yīng)該調(diào)用哪一個函數(shù),必須在程序的執(zhí)行過程中,根據(jù)具體的執(zhí)行情況來動態(tài)地確定可以將一個派生類對象的地址賦給基類的指針變量?;悓ο笈缮悓ο驜aseb;Derived;Base*basep;basepbasep=&b;basepbasep=&d;basep只能引用從基類繼承來的成員。xShow()xShow()yShow()basep->Show();basep->Show()基類指針派生類對象基類對象classPoint{ floatx,y;public: Point(){} Point(floati,floatj){ x=i; y=j; }

floatarea(void) { return0.0; }};constfloatPi=3.14159;classCircle:publicPoint{ //類Point的派生類

floatradius;public: Circle(floatr){ radius=r; }

floatarea(void) {returnPi*radius*radius; }};voidmain(void){Point*pp; //基類指針,可以將派生類對象的地址賦給基類指針

Circlec(5.4321);pp=&c;cout<<pp->area()<<endl; //調(diào)用的是基類中有的公有函數(shù)}在基類和派生類中具有相同的公有函數(shù)area()。在這種情況下,使用基類的指針時,只能訪問從相應(yīng)基類中繼承來的成員,而不允許訪問在派生類中增加的成員。輸出為0基類對象派生類對象Baseb;Derived;basepbasepxShow()xShow()yShow()basep->Show()Base*basep;basep=&b;basep=&d;basep->Show();即指向派生類新增的成員函數(shù)需要將基類中的Show()說明為虛函數(shù)若要訪問派生類中相同名字的函數(shù),必須將基類中的同名函數(shù)定義為虛函數(shù),這樣,將不同的派生類對象的地址賦給基類的指針變量后,就可以動態(tài)地根據(jù)這種賦值語句調(diào)用不同類中的函數(shù)。classPoint{floatx,y;public: Point(){} Point(floati,floatj){ x=i; y=j; }

virtual

floatarea(void) {return0.0;}};constfloatPi=3.14159;classCircle:publicPoint{ //類Point的派生類

floatradius;public: Circle(floatr){ radius=r; }

floatarea(void) {returnPi*radius*radius;}};voidmain(void){Point*pp; //基類指針,可以將派生類對象的地址賦給基類指針

Circlec(5.4321);pp=&c;cout<<pp->area()<<endl;//調(diào)用虛函數(shù)}將area()聲明為虛函數(shù),編譯器對其進(jìn)行動態(tài)聚束,按照實際對象c調(diào)用了Circle中的函數(shù)area()。使Point類中的area()與Circle類中的area()有一個統(tǒng)一的接口。輸出:92.7011聲明為虛函數(shù)調(diào)用虛函數(shù)虛函數(shù)再定義虛函數(shù)的定義和使用

可以在程序運行時通過調(diào)用相同的函數(shù)名而實現(xiàn)不同功能的函數(shù)稱為虛函數(shù)。定義格式為:virtual<type>FuncName(<ArgList>);一旦把基類的成員函數(shù)定義為虛函數(shù),由基類所派生出來的所有派生類中,該函數(shù)均保持虛函數(shù)的特性。在派生類中重新定義基類中的虛函數(shù)時,可以不用關(guān)鍵字virtual來修飾這個成員函數(shù)。虛函數(shù)是用關(guān)鍵字virtual修飾的某基類中的protected或public成員函數(shù)。它可以在派生類中重新定義,以形成不同版本。只有在程序的執(zhí)行過程中,依據(jù)指針具體指向哪個類對象,或依據(jù)引用哪個類對象,才能確定激活哪一個版本,實現(xiàn)動態(tài)聚束。classA{protected: intx;public: A(){x=1000;}

virtualvoidprint(){ cout<<“x=”<<x<<‘\t’; }//虛函數(shù)};classB:publicA{ inty;public: B(){y=2000;}

voidprint(){ cout<<“y=”<<y<<‘\t’; }//派生虛函數(shù)}; classC:publicA{ intz;public: C(){z=3000;}

voidprint(){ cout<<“z=”<<z<<‘\n’; }//派生虛函數(shù)};voidmain(void){Aa,*pa;Bb; Cc;a.print();b.print(); c.print();//靜態(tài)調(diào)用

pa=&a;pa->print();//調(diào)用類A的虛函數(shù)

pa=&b;pa->print();//調(diào)用類B的虛函數(shù)

pa=&c;pa->print();}//調(diào)用類C的虛函數(shù)classBase{public:virtualintSet(inta,intb){.....}....};classDerive:publicBase{public:intSet(intx,inty){.....}.....};classBase{public:virtualintSet(inta,intb){.....}....};classDerive:publicBase{public:intSet(intx,inty=0){.....}.....};intSet(int,int)是虛函數(shù)兩個Set()函數(shù)參數(shù)不一致,是重載,不是虛函數(shù)關(guān)于虛函數(shù),說明以下幾點:1、當(dāng)在基類中把成員函數(shù)定義為虛函數(shù)后,在其派生類中定義的虛函數(shù)必須與基類中的虛函數(shù)同名,參數(shù)的類型、順序、參數(shù)的個數(shù)必須一一對應(yīng),函數(shù)的返回的類型也相同。若函數(shù)名相同,但參數(shù)的個數(shù)不同或者參數(shù)的類型不同時,則屬于函數(shù)的重載,而不是虛函數(shù)。若函數(shù)名不同,顯然這是不同的成員函數(shù)。2、實現(xiàn)這種動態(tài)的多態(tài)性時,必須使用基類類型的指針變量,并使該指針指向不同的派生類對象,并通過調(diào)用指針?biāo)赶虻奶摵瘮?shù)才能實現(xiàn)動態(tài)的多態(tài)性。xShow()xShow()yShow()xShow()zShow()類A類B類CShow()定義為虛函數(shù)類B與類C均為類A的公有派生。A*p;Bb;Cc;p=&b;p->Show();p=&c;p->Show();即在程序運行時,通過賦值語句實現(xiàn)多態(tài)性3、虛函數(shù)必須是類的一個成員函數(shù),不能是友元函數(shù),也不能是靜態(tài)的成員函數(shù)。4、在派生類中沒有重新定義虛函數(shù)時,與一般的成員函數(shù)一樣,當(dāng)調(diào)用這種派生類對象的虛函數(shù)時,則調(diào)用其基類中的虛函數(shù)。5、可把析構(gòu)函數(shù)定義為虛函數(shù),但是,不能將構(gòu)造函數(shù)定義為虛函數(shù)。6、虛函數(shù)與一般的成員函數(shù)相比較,調(diào)用時的執(zhí)行速度要慢一些。為了實現(xiàn)多態(tài)性,在每一個派生類中均要保存相應(yīng)虛函數(shù)的入口地址表,函數(shù)的調(diào)用機制也是間接實現(xiàn)的。因此,除了要編寫一些通用的程序,并一定要使用虛函數(shù)才能完成其功能要求外,通常不必使用虛函數(shù)。7、一個函數(shù)如果被定義成虛函數(shù),則不管經(jīng)歷多少次派生,仍將保持其虛特性,以實現(xiàn)“一個接口,多個形態(tài)”。虛函數(shù)的訪問用基指針訪問與用對象名訪問用基指針訪問虛函數(shù)時,指向其實際派生類對象重新定義的函數(shù)。實現(xiàn)動態(tài)聚束。通過一個對象名訪問時,只能靜態(tài)聚束。即由編譯器在編譯的時候決定調(diào)用哪個函數(shù)。classPoint{floatx,y;public: Point(){} Point(floati,floatj){ x=i; y=j; }

virtual

floatarea(void) {return0.0;}//聲明為虛函數(shù)};constfloatPi=3.14159;classCircle:publicPoint{ //類Point的派生類

floatradius;public: Circle(floatr){ radius=r; }

floatarea(void) {returnPi*radius*radius;}//虛函數(shù)再定義};voidmain(void){Point*pp; //基類指針,可以將派生類對象的地址賦給基類指針

Circlec(5.4321);cout<<c.area()<<endl;cout<<c.Point::area()<<endl; cout<<c.Circle::area()<<endl;}輸出:92.7011 0 92.7011可見,利用對象名進(jìn)行調(diào)用與一般非虛函數(shù)沒有區(qū)別。用對象名調(diào)用area()classbase0{public: voidv(void){ cout<<"base0\n"; }};classbase1:publicbase0{public: virtualvoidv(void){cout<<"base1\n";}};classA1:publicbase1{public: voidv(){ cout<<"A1\n"; }};classA2:publicA1{public: voidv(void){ cout<<"A2\n"; }};classB1:privatebase1{public: voidv(void){ cout<<"B1\n"; }};classB2:publicB1{public: voidv(void){ cout<<"B2\n"; }};voidmain(void){base0*pb;A1a1;(pb=&a1)->v();A2a2;(pb=&a2)->v();B1b1;

(pb=&b1)->v();B2b2;

(pb=&b2)->v();}base0base0私有派生,在類外不能調(diào)用基類函數(shù)classbase0{public: voidv(void){ cout<<"base0\n"; }};classbase1:publicbase0{public: virtualvoidv(void){cout<<"base1\n";}};classA1:publicbase1{public: voidv(){ cout<<"A1\n"; }};classA2:publicA1{public: voidv(void){ cout<<"A2\n"; }};classB1:privatebase1{public: voidv(void){ cout<<"B1\n"; }};classB2:publicB1{public: voidv(void){ cout<<"B2\n"; }};voidmain(void){base1*pb;A1a1;(pb=&a1)->v();A2a2;(pb=&a2)->v();}A1A2純虛函數(shù)在基類中不對虛函數(shù)給出有意義的實現(xiàn),它只是在派生類中有具體的意義。這時基類中的虛函數(shù)只是一個入口,具體的目的地由不同的派生類中的對象決定。這個虛函數(shù)稱為純虛函數(shù)。class<基類名>{ virtual<類型><函數(shù)名>(<參數(shù)表>)=0; ......};classA{protected: intx;public: A(){x=1000;}

virtualvoidprint()=0;//定義純虛函數(shù)};classB:publicA{//派生類private:inty;public: B(){y=2000;}

voidprint(){cout<<“y=”<<y<<‘\n’;}//重新定義純虛函數(shù)};

classC:publicA{//派生類

intz;public: C(){z=3000;}

voidprint(){cout<<“z=”<<z<<‘\n’;}//重新定義純虛函數(shù)};voidmain(void){A*pa; Bb; Cc;pa=&b;pa->print(); pa=&c;pa->print();

Aa;pa=&a;pa->print();}y=2000z=3000抽象類不能定義抽象類的對象1、在定義純虛函數(shù)時,不能定義虛函數(shù)的實現(xiàn)部分。2、把函數(shù)名賦于0,本質(zhì)上是將指向函數(shù)體的指針值賦為初值0。與定義空函數(shù)不一樣,空函數(shù)的函數(shù)體為空,即調(diào)用該函數(shù)時,不執(zhí)行任何動作。在沒有重新定義這種純虛函數(shù)之前,是不能調(diào)用這種函數(shù)的。3、把至少包含一個純虛函數(shù)的類,稱為抽象類。這種類只能作為派生類的基類,不能用來說明這種類的對象。其理由是明顯的:因為虛函數(shù)沒有實現(xiàn)部分,所以不能產(chǎn)生對象。但可以定義指向抽象類的指針,即指向這種基類的指針。當(dāng)用這種基類指針指向其派生類的對象時,必須在派生類中重載純虛函數(shù),否則會產(chǎn)生程序的運行錯誤。4、在以抽象類作為基類的派生類中必須有純虛函數(shù)的實現(xiàn)部分,即必須有重載純虛函數(shù)的函數(shù)體。否則,這樣的派生類也是不能產(chǎn)生對象的。綜上所述,可把純虛函數(shù)歸結(jié)為:抽象類的唯一用途是為派生類提供基類,純虛函數(shù)的作用是作為派生類中的成員函數(shù)的基礎(chǔ),并實現(xiàn)動態(tài)多態(tài)性。虛基類多基派生中的多條路徑具有公共基類時,在這條路徑的匯合處就會因?qū)不惍a(chǎn)生多個拷貝而產(chǎn)生同名函數(shù)調(diào)用的二義性。解決這個問題的辦法就是把公共基類定義為虛基類,使由它派生的多條路徑的匯聚處只產(chǎn)生一個拷貝。classBase{};classA:publicBase{};classB:publicBase{};classC:publicA,publicB{};類C中繼承了兩個類Base,即有兩個類Base的實現(xiàn)部分,在調(diào)用時產(chǎn)生了二義性。用虛基類進(jìn)行多重派生時,若虛基類沒有缺省的構(gòu)造函數(shù),則在每一個派生類的構(gòu)造函數(shù)中都必須有對虛基類構(gòu)造函數(shù)的調(diào)用(且首先調(diào)用)。由虛基類派生出的對象初始化時,直接調(diào)用虛基類的構(gòu)造函數(shù)。因此,若將一個類定義為虛基類,則一定有正確的構(gòu)造函數(shù)可供所有派生類調(diào)用。classbase{public:virtualvoida(){ cout<<"a()inbase\n";}virtualvoidb(){ cout<<"b()inbase\n";}virtualvoidc(){ cout<<"c()inbase\n";}virtualvoidd(){ cout<<"d()inbase\n";}virtualvoide(){ cout<<"e()inbase\n";}virtualvoidf(){ cout<<"f()inbase\n";}};classA:publicbase{public: virtualvoida(){ cout<<"a()inA\n";}virtualvoidb(){ cout<<"b()inA\n";}virtualvoidf(){ cout<<"f()inA\n";}};classB:publicbase{public:virtualvoida(){ cout<<"a()inB\n";}virtualvoidb(){ cout<<"b()inB\n";}virtualvoidc(){ cout<<"c()inB\n";}};classC:publicA,publicB{public: virtualvoida(){ cout<<"a()inC\n";}virtualvoidd(){ cout<<"d()inC\n";}};voidmain(void){Ccc;

base*pbase=&cc;//錯誤

A*pa=&cc;pa->a();pa->b();pa->c();pa->d();pa->e();pa->f();}將類C的地址賦值時產(chǎn)生歧義a()b()c()d()e()f()a()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()a()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()baseABCa()d()ABclassbase{public:virtualvoida(){ cout<<"a()inbase\n";}virtualvoidb(){ cout<<"b()inbase\n";}virtualvoidc(){ cout<<"c()inbase\n";}virtualvoidd(){ cout<<"d()inbase\n";}virtualvoide(){ cout<<"e()inbase\n";}virtualvoidf(){ cout<<"f()inbase\n";}};classA:publicbase{public: virtualvoida(){ cout<<"a()inA\n";}virtualvoidb(){ cout<<"b()inA\n";}virtualvoidf(){ cout<<"f()inA\n";}};classB:publicbase{public:virtualvoida(){ cout<<"a()inB\n";}virtualvoidb(){ cout<<"b()inB\n";}virtualvoidc(){ cout<<"c()inB\n";}};classC:publicA,publicB{public: virtualvoida(){ cout<<"a()inC\n";}virtualvoidd(){ cout<<"d()inC\n";}};voidmain(void){Ccc;

base*pbase=&cc;//錯誤

A*pa=&cc;pa->a();pa->b();pa->c();pa->d();pa->e();pa->f();}將類C的地址賦值時產(chǎn)生歧義類C中有兩個base,只有一個Aa()inCb()inAc()inbased()inCe()inbasef()inA為避免這種情況,將base定義為虛基類。classbase{public:virtualvoida(){ cout<<"a()inbase\n";}virtualvoidb(){ cout<<"b()inbase\n";}virtualvoidc(){ cout<<"c()inbase\n";}virtualvoidd(){ cout<<"d()inbase\n";}virtualvoide(){ cout<<"e()inbase\n";}virtualvoidf(){ cout<<"f()inbase\n";}};classA:virtualpublicbase{public: virtualvoida(){ cout<<"a()inA\n";}virtualvoidb(){ cout<<"b()inA\n";}virtualvoidf(){ cout<<"f()inA\n";}};classB:virtualpublicbase{public:virtualvoida(){ cout<<"a()inB\n";}virtualvoidc(){ cout<<"c()inB\n";}};classC:publicA,publicB{public: virtualvoida(){ cout<<"a()inC\n";}virtualvoidd(){ cout<<"d()inC\n";}};voidmain(void){Ccc;base*pa=&cc;pa->a();pa->b();pa->c();pa->d();pa->e();pa->f();}a()b()c()d()e()f()a()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()a()b()c()d()e()f()a()b()f()a()c()baseABCa()d()ABclassbase{public:virtualvoida(){ cout<<"a()inbase\n";}virtualvoidb(){ cout<<"b()inbase\n";}virtualvoidc(){ cout<<"c()inbase\n";}virtualvoidd(){ cout<<"d()inbase\n";}virtualvoide(){ cout<<"e()inbase\n";}virtualvoidf(){ cout<<"f()inbase\n";}};classA:virtualpublicbase{public: virtualvoida(){ cout<<"a()inA\n";}virtualvoidb(){ cout<<"b()inA\n";}virtualvoidf(){ cout<<"f()inA\n";}};classB:virtualpublicbase{public:virtualvoida(){ cout<<"a()inB\n";}virtualvoidc(){ cout<<"c()inB\n";}};classC:publicA,publicB{public: virtualvoida(){ cout<<"a()inC\n";}virtualvoidd(){ cout<<"d()inC\n";}};voidmain(void){Ccc;base*pa=&cc;pa->a();pa->b();pa->c();pa->d();pa->e();pa->f();}類C中只有一個basea()inCb()inAc()inBd()inCe()inbasef()inAclassbase{public:voida(){cout<<"a()inbase\n";}voidb(){cout<<"b()inbase\n";}voidc(){ cout<<"c()inbase\n";}voidd(){cout<<"d()inbase\n";}voide(){ cout<<"e()inbase\n";}voidf(){ cout<<"f()inbase\n";}};classA:virtualpublicbase{public: voida(){cout<<"a()inA\n";}voidb(){cout<<"b()inA\n";}voidf(){ cout<<"f()inA\n";}};classB:virtualpublicbase{public:voida(){cout<<"a()inB\n";}voidc(){ cout<<"c()inB\n";}};classC:publicA,publicB{public: voida(){ cout<<"a()inC\n";}voidd(){ cout<<"d()inC\n";}};voidmain(void){Ccc;base*pa=&cc;pa->a();pa->b();pa->c();pa->d();pa->e();pa->f();}類C中只有一個basea()inbaseb()inbasec()inbased()inbasee()inbasef()inbase下面程序的輸出是

。classA{protected:intx;public:A(){x=1000;}virtualvoidp(){cout<<"x="<<x<<'\n';p2();}virtualvoidp2(){cout<<"A::p2()"<<endl;}};classC:publicA{ intz;public:C(){z=3000;}voidp(){cout<<"z="<<z<<'\n';p2();}virtualvoidp2(){cout<<"C::p2()"<<endl;}};voidmain(void){Cc;Aa,*pa=&a;pa->p();pa=&c;pa->p();}

通常,每當(dāng)說明一個對象時,把該類中的有關(guān)成員數(shù)據(jù)拷貝到該對象中,即同一類的不同對象,其成員數(shù)據(jù)之間是互相獨立的。靜態(tài)成員classA{intx,y;public:voidSetxy(inta,intb){x=a;y=b;}};Aa1,a2;a1.xa1.ya2.xa2.y......x=a;y=b;......a1.Setxy()a2.Setxy()a1.Setxy(1,2);a2.Setxy(3,4);this->x=a;this->y=b;當(dāng)我們將類的某一個數(shù)據(jù)成員的存儲類型指定為靜態(tài)類型時,則由該類所產(chǎn)生的所有對象,其靜態(tài)成員均共享一個存儲空間,這個空間是在編譯的時候分配的。換言之,在說明對象時,并不為靜態(tài)類型的成員分配空間。在類定義中,用關(guān)鍵字static修飾的數(shù)據(jù)成員稱為靜態(tài)數(shù)據(jù)成員。classA{intx,y;staticintz;public:voidSetxy(inta,intb){x=a;y=b;}};Aa1,

a2;a1.xa1.ya2.xa2.yza1.za2.z不同對象,同一空間有關(guān)靜態(tài)數(shù)據(jù)成員的使用,說明以下幾點:1、類的靜態(tài)數(shù)據(jù)成員是靜態(tài)分配存儲空間的,而其它成員是動態(tài)分配存儲空間的(全局變量除外)。當(dāng)類中沒有定義靜態(tài)數(shù)據(jù)成員時,在程序執(zhí)行期間遇到說明類的對象時,才為對象的所有成員依次分配存儲空間,這種存儲空間的分配是動態(tài)的;而當(dāng)類中定義了靜態(tài)數(shù)據(jù)成員時,在編譯時,就要為類的靜態(tài)數(shù)據(jù)成員分配存儲空間。2、必須在文件作用域中,對靜態(tài)數(shù)據(jù)成員作一次且只能作一次定義性說明。因為靜態(tài)數(shù)據(jù)成員在定義性說明時已分配了存儲空間,所以通過靜態(tài)數(shù)據(jù)成員名前加上類名和作用域運算符,可直接引用靜態(tài)數(shù)據(jù)成員。在C++中,靜態(tài)變量缺省的初值為0,所以靜態(tài)數(shù)據(jù)成員總有唯一的初值。當(dāng)然,在對靜態(tài)數(shù)據(jù)成員作定義性的說明時,也可以指定一個初值。classA{ inti,j;

staticintx,y;//定義靜態(tài)成員public: A(inta=0,intb=0,intc=0,intd=0){ i=a;j=b;x=c;y=d; } voidShow(){cout<<"i="<<i<<'\t'<<"j="<<j<<'\t'; cout<<"x="<<x<<'\t'<<"y="<<y<<"\n"; }};intA::x=0;//必須對靜態(tài)成員作一次定義性說明intA::y=0;

voidmain(void){ Aa(2,3,4,5); a.Show(); Ab(100,200,300,400); b.Show(); a.Show();}a.x和b.x在內(nèi)存中占據(jù)一個空間a.y和b.y在內(nèi)存中占據(jù)一個空間i=2 j=3 x=4 y=5i=100 j=200 x=300 y=400i=2 j=3 x=300 y=400classA{ inti,j;public:staticintx;public:A(inta=0,intb=0,intc=0){i=a;j=b;x=c; } voidShow(){ cout<<"i="<<i<<'\t'<<"j="<<j<<'\t'; cout<<"x="<<x<<"\n"; }};intA::x=500; //intA::xvoidmain(void){ Aa(20,40,10),b(30,50,100); a.Show(); b.Show(); cout<<“A::x=”<<A::x<<‘\n’;//可以直接用類名引用 }在類外重新定義3、靜態(tài)數(shù)據(jù)成員具有全局變量和局部變量的一些特性。靜態(tài)數(shù)據(jù)成員與全局變量一樣都是靜態(tài)分配存儲空間的,但全局變量在程序中的任何位置都可以訪問它,而靜態(tài)數(shù)據(jù)成員受到訪問權(quán)限的約束。必須是public權(quán)限時,才可能在類外進(jìn)行訪問。4、為了保持靜態(tài)數(shù)據(jù)成員取值的一致性,通常在構(gòu)造函數(shù)中不給靜態(tài)數(shù)據(jù)成員置初值,而是在對靜態(tài)數(shù)據(jù)成員的定義性說明時指定初值。classA{ inti;

staticintcount;public:

A(inta=0) {i=a;count++; cout<<"NumberofObjects="<<count<<'\n'; } ~A() {count--;cout<<"NumberofObjects="<<count<<'\n'; }

voidShow() {cout<<"i="<<i<<'\n';cout<<"count="<<count<<"\n";}};intA::count;voidmain(void){ Aa1(100); Ab[2]; a1.Show();}NumberofObjects=1NumberofObjects=2NumberofObjects=3i=100count=3NumberofObjects=2NumberofObjects=1NumberofObjects=0靜態(tài)成員函數(shù)可以將類的成員函數(shù)定義為靜態(tài)的成員函數(shù)。即使用關(guān)鍵字static來修飾成員函數(shù)。classA{floatx,y;public:A(){}staticvoidsum(void){.....}};對靜態(tài)成員函數(shù)的用法說明以下幾點:1、與靜態(tài)數(shù)據(jù)成員一樣,在類外的程序代碼中,通過類名加上作用域操作符,可直接調(diào)用靜態(tài)成員函數(shù)。2、靜態(tài)成員函數(shù)只能直接使用本類的靜態(tài)數(shù)據(jù)成員或靜態(tài)成員函數(shù),但不能直接使用非靜態(tài)的數(shù)據(jù)成員(可以引用使用)。這是因為靜態(tài)成員函數(shù)可被其它程序代碼直接調(diào)用,所以,它不包含對象地址的this指針。classTc{private:intA;

staticintB;//靜態(tài)數(shù)據(jù)成員public:Tc(inta){A=a;B+=a;}

staticvoiddisplay(Tcc)//Tc的對象為形參

{ cout<<"A="<<c.A<<",B="<<B<<endl; }};intTc::B=2;voidmain(void){ Tca(2),b(4);

Tc::display(a);

Tc::display(b);}非靜態(tài)成員,用對象名來引用靜態(tài)成員,直接引用直接用類名來調(diào)用靜態(tài)成員函數(shù)A=2,B=8A=4,B=83、靜態(tài)成員函數(shù)的實現(xiàn)部分在類定義之外定義時,其前面不能加修飾詞static。這是由于關(guān)鍵字static不是數(shù)據(jù)類型的組成部分,因此,在類外定義靜態(tài)成員函數(shù)的實現(xiàn)部分時,不能使用這個關(guān)鍵字4、不能把靜態(tài)成員函數(shù)定義為虛函數(shù)。靜態(tài)成員函數(shù)也是在編譯時分配存儲空間,所以在程序的執(zhí)行過程中不能提供多態(tài)性。5、可將靜態(tài)成員函數(shù)定義為內(nèi)聯(lián)的(inline),其定義方法與非靜態(tài)成員函數(shù)完全相同。classTc{private:intA;

staticintB;//靜態(tài)數(shù)據(jù)成員public:Tc(inta){A=a;B+=a;}

staticvoiddisplay(Tcc);//Tc的對象為形參};voidTc::display(Tcc)//不用static修飾

{cout<<"A="<<c.A<<",B="<<B<<endl; }intTc::B=2;voidmain(void){ Tca(2),b(4);

Tc::display(a);

Tc::display(b);}函數(shù)原型

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論