c++程序設計 -11-類的其它特性_第1頁
c++程序設計 -11-類的其它特性_第2頁
c++程序設計 -11-類的其它特性_第3頁
c++程序設計 -11-類的其它特性_第4頁
c++程序設計 -11-類的其它特性_第5頁
已閱讀5頁,還剩68頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、1第十一章第十一章 類的其它特性類的其它特性 2友元函數友元函數類中私有和保護的成員在類外不能被訪問。類中私有和保護的成員在類外不能被訪問。友元函數是一種定義在類外部的友元函數是一種定義在類外部的普通函普通函數數,其特點是,其特點是能夠訪問類中私有成員和能夠訪問類中私有成員和保護成員保護成員,即類的訪問權限的限制對其,即類的訪問權限的限制對其不起作用。不起作用。3友元函數需要在友元函數需要在類體內類體內進行說明,在前面加進行說明,在前面加上關鍵字上關鍵字friend。一般格式為:一般格式為:friend FuncName();friend float Volume(A &a);關鍵字關

2、鍵字返回值類型返回值類型函數名函數名函數參數函數參數4友元函數不是成員函數友元函數不是成員函數,用法也與普通,用法也與普通的函數完全一致,的函數完全一致,只不過它能訪問類中只不過它能訪問類中所有的數據所有的數據。友元函數破壞了類的封裝友元函數破壞了類的封裝性和隱蔽性,使得非成員函數可以訪問性和隱蔽性,使得非成員函數可以訪問類的私有成員類的私有成員。一個類的友元可以自由地用該類中的所有成員。一個類的友元可以自由地用該類中的所有成員。5class Afloat x,y;public: A(float a, float b) x=a; y=b; float Sum() return x+y; fri

3、end float Sum(A &a) return a.x+a.y; ;void main(void) A t1(4,5),t2(10,20); coutt1.Sum()endl; coutSum(t2)endl;友元函數友元函數成員函數成員函數友元函數的調用,直接調用友元函數的調用,直接調用成員函數的調用,利用對象名調用成員函數的調用,利用對象名調用友元函數只能用友元函數只能用對象對象名名引用類中的數據。引用類中的數據。私有數據私有數據6有關友元函數的使用,說明如下:有關友元函數的使用,說明如下:友元函數不是類的成員函數友元函數不是類的成員函數友元函數近似于友元函數近似于普通的函數

4、普通的函數,它不帶有,它不帶有this指針,指針,因此必須將對象名或對象的引用作為因此必須將對象名或對象的引用作為友元函數的參數友元函數的參數,這樣才能訪問到對象的成,這樣才能訪問到對象的成員。員。7友元函數與一般函數的不同點在于友元函數與一般函數的不同點在于:1.友元函數必須在類的定義中說明,友元函數必須在類的定義中說明,其其函數體可在類內定義,也可在類外定函數體可在類內定義,也可在類外定義義;2.它可以訪問該類中的所有成員(公有它可以訪問該類中的所有成員(公有的、私有的和保護的)的、私有的和保護的),而一般函數,而一般函數只能訪問類中的公有成員。只能訪問類中的公有成員。8class Afl

5、oat x,y;public: A(float a, float b) x=a; y=b; float Getx() return x; float Gety() return y; float Sum() return x+y; friend float Sum(A &); ;float Sumxy(A &a) return a.Getx()+a.Gety(); float Sum(A &a) return a.x+a.y; void main(void) A t1(1,2),t2(10,20), t3(100,200); coutt1.Sum()endl; cout

6、Sum(t2)endl; coutSumxy(t3)endl;成員函數成員函數友元函數友元函數,可以直接調用類中私有成員可以直接調用類中私有成員普通函數,必須通過公有函數訪問私有成員普通函數,必須通過公有函數訪問私有成員對象調用成員函數對象調用成員函數調用友元函數調用友元函數調用一般函數調用一般函數友元函數友元函數9友元函數不受類中訪問權限關鍵字的限制,可以友元函數不受類中訪問權限關鍵字的限制,可以把它放在類的私有部分,放在類的公有部分或放把它放在類的私有部分,放在類的公有部分或放在類的保護部分,其作用都是一樣的。換言之,在類的保護部分,其作用都是一樣的。換言之,在類中對友元函數指定訪問權限是

7、不起作用的在類中對友元函數指定訪問權限是不起作用的。友元函數的作用域與一般函數的作用域相同。友元函數的作用域與一般函數的作用域相同。謹慎使用友元函數謹慎使用友元函數通常使用友元函數來通常使用友元函數來取取對象中的數據成員值,而對象中的數據成員值,而不修改不修改對象中的成員值,則肯定是安全的。對象中的成員值,則肯定是安全的。10大多數情況是友元函數是某個類的成員函數,大多數情況是友元函數是某個類的成員函數,即即A類中的某個成員函數是類中的某個成員函數是B類中的友元函數,這個成類中的友元函數,這個成員函數可以直接訪問員函數可以直接訪問B類中的私有數據。類中的私有數據。這就實現這就實現了類與類之間的

8、溝通了類與類之間的溝通。注意:一個類的成員函數作為另一個類的友元函數時,注意:一個類的成員函數作為另一個類的友元函數時,應應先定義友元函數所在的類。先定義友元函數所在的類。class A.void fun( B &);class B.friend void fun( B &);既是類既是類A的成員函數的成員函數又是類又是類B的友元函數的友元函數11class B ;/先定義類先定義類A,則首先對類,則首先對類B作引用性說明作引用性說明class A ./類類A的成員定義的成員定義 public: void fun( B & );/函數的原型說明函數的原型說明 ;clas

9、s B. friend void A:fun( B & );/定義友元函數定義友元函數; void A:fun ( B &b) /函數的完整定義函數的完整定義 ./函數體的定義函數體的定義類類A中的成員函數中的成員函數fun()是類是類B的友元函的友元函數。即在數。即在fun()中可中可以直接引用類以直接引用類B的私的私有成員。有成員。12class B;/必須在此進行引用性說明,必須在此進行引用性說明,class Afloat x,y;public: A(float a, float b) x=a; y=b; float Sum(B &); /說明友元函數的函數原型,

10、是類說明友元函數的函數原型,是類A的一成員函數的一成員函數;class Bfloat m,n;public: B(float a,float b) m=a;n=b; friend float A:Sum(B &);/說明類說明類A的成員函數是類的成員函數是類B的友元函數的友元函數float A:Sum( B &b)/定義該友元函數定義該友元函數 x=b.m+b.n; y=b.m-b.n; void main(void) A a1(3,5); B b1(10,20); a1.Sum(b1); /調用該函數,調用該函數,因是類因是類A的成員函數,故用類的成員函數,故用類A的對象調用

11、的對象調用a1.x=30a1.y=-10直接引用類直接引用類B的私有成員的私有成員類類A中有一個函數可以直中有一個函數可以直接引用類接引用類B的私有成員的私有成員13友元類友元類class A . friend class B;class B . 類類B是類是類A的友元的友元類類B可以自由使用可以自由使用類類A中的成員中的成員對于類對于類B而言,類而言,類A是透明的是透明的類類B必須通過必須通過類類A的對象的對象使用類使用類A的成員的成員14const float PI =3.1415926;class Afloat r ;float h;public: A(float a,float b)r

12、=a; h=b;float Getr()return r;float Geth()return h;friend class B;/定義類定義類B為類為類A的友元的友元;class B int number;public: B(int n=1)number=n;void Show(A &a) coutPI*a.r*a.r*a.h*numberendl; /求類求類A的某個對象的某個對象*n的體積的體積;void main(void)A a1(25,40),a2(10,40);B b1(2);b1.Show (a1); b1.Show (a2);直接引用類直接引用類A的私有成員的私有成員

13、類類B中的任何函數都中的任何函數都能使用類能使用類A中的所有中的所有私有成員。私有成員。15不管是按哪一種方式派生,基類的私有成員不管是按哪一種方式派生,基類的私有成員在派生類中都是不可見的。在派生類中都是不可見的。如果在一個派生類中要訪問基類中的私有成如果在一個派生類中要訪問基類中的私有成員,可以將這個員,可以將這個派生類聲明為基類的友元派生類聲明為基類的友元。class Base friend class Derive; .class Derive .直接使用直接使用Base中的私有成員中的私有成員16#includeclass M friend class N; /N為為M的友元,可以直

14、接使用的友元,可以直接使用M中的私有成員中的私有成員private: int i , j; void show(void)couti=itj=jt;public: M(int a=0,int b=0) i=a; j=b;class N :public M /N為為M的派生類的派生類public: N(int a=0,int b=0):M(a,b) void Print(void) show(); couti+j=i+jendl;void main(void) N n1(10,20); M m1(100,200);/ m1.show();/私有成員函數,在類外不可調用私有成員函數,在類外不可調用

15、 n1.Print();直接引用類直接引用類M的私有成員函數和私有成員的私有成員函數和私有成員17基類對象基類對象 M派生類對象派生類對象 Nx(私有)私有)Show( )(私有私有)x(私私有)私私有)Show( )(私私有私私有)y(公有公有)Showy( )(公有公有)showy( ) show(); coutiShow();basep-Show()基類指針基類指針派生類對象派生類對象基類對象基類對象20class Pointfloat x,y;public: Point()Point(float i,float j)x=i;y=j;float area(void) return 0.0

16、;const float Pi=3.14159;class Circle:public Point/類類Point的派生類的派生類float radius;public: Circle(float r)radius=r;float area(void) return Pi*radius*radius;void main(void) Point *pp; /基類指針,可以將派生類對象的地址賦給基類指針基類指針,可以將派生類對象的地址賦給基類指針 Circle c(5.4321); pp=&c; coutarea ()Show()Base *basep;basep=&b;basep

17、 = &d;basep -Show();即指向派生類新增的成員函數即指向派生類新增的成員函數需要將基類中的需要將基類中的Show()說明為虛函數說明為虛函數22若要訪問派生類中相同名字的函數,必須將若要訪問派生類中相同名字的函數,必須將基類中的基類中的同名函數定義為虛函數同名函數定義為虛函數,這樣,將,這樣,將不同的派生類對象的地址賦給基類的指針變不同的派生類對象的地址賦給基類的指針變量后,就可以量后,就可以動態(tài)地根據這種賦值語句調用動態(tài)地根據這種賦值語句調用不同類中的函數不同類中的函數。23class Point float x,y;public: Point()Point(floa

18、t i,float j)x=i;y=j;virtual float area(void) return 0.0; ;const float Pi=3.14159;class Circle:public Point/類類Point的派生類的派生類float radius;public: Circle(float r)radius=r;float area(void) return Pi*radius*radius;void main(void) Point *pp; /基類指針,可以將派生類對象的地址賦給基類指針基類指針,可以將派生類對象的地址賦給基類指針 Circle c(5.4321); p

19、p=&c; coutarea ()endl; /調用虛函數調用虛函數將將area()聲明為虛函數,編譯器對其進行動態(tài)聚束,按照實際對象聲明為虛函數,編譯器對其進行動態(tài)聚束,按照實際對象c調用了調用了Circle中的函數中的函數area()。使。使Point類中的類中的area()與與Circle類中的類中的area()有一個統(tǒng)一有一個統(tǒng)一的接口。的接口。輸出:輸出:92.7011聲明為虛函數聲明為虛函數調用虛函數調用虛函數虛函數再定義虛函數再定義24虛函數的定義和使用虛函數的定義和使用 可以在程序運行時通過調用相同的函數名而實可以在程序運行時通過調用相同的函數名而實現不同功能的函數稱為

20、虛函數。現不同功能的函數稱為虛函數。定義格式為:定義格式為:virtual FuncName();一旦把基類的成員函數定義為虛函數,由基類所一旦把基類的成員函數定義為虛函數,由基類所派生出來的所有派生類中,該函數均保持虛函數派生出來的所有派生類中,該函數均保持虛函數的特性。的特性。 在派生類中重新定義基類中的虛函數時,可以不在派生類中重新定義基類中的虛函數時,可以不用關鍵字用關鍵字virtual來修飾這個成員函數來修飾這個成員函數 。25虛函數是用關鍵字虛函數是用關鍵字virtual修飾的某基類中的修飾的某基類中的protected或或public成員函數。它可以在派生成員函數。它可以在派生類

21、中重新定義,以形成不同版本。類中重新定義,以形成不同版本。只有在程只有在程序的執(zhí)行過程中,依據指針具體指向哪個類序的執(zhí)行過程中,依據指針具體指向哪個類對象,或依據引用哪個類對象,才能確定激對象,或依據引用哪個類對象,才能確定激活哪一個版本,實現動態(tài)聚束活哪一個版本,實現動態(tài)聚束。26class Aprotected:int x;public: A()x =1000; virtual void print()cout “x=”xt;/虛函數虛函數;class B:public Aint y;public: B() y=2000;void print()cout “y=”yt;/派生虛函數派生虛函

22、數;class C:public Aint z;public: C()z=3000;void print()cout “z=”zprint();/調用類調用類A的虛函數的虛函數 pa=&b; pa-print();/調用類調用類B的虛函數的虛函數 pa=&c; pa-print();/調用類調用類C的虛函數的虛函數27class Base public : virtual int Set(int a, int b) . .;class Derive:public Basepublic : int Set(int x, int y) . .;class Base public :

23、 virtual int Set(int a, int b) . .;class Derive:public Basepublic : int Set(int x, int y=0) . .;int Set(int ,int )是虛函數是虛函數兩個兩個Set()函數參數函數參數不一致,是重載,不一致,是重載,不是虛函數不是虛函數28關于虛函數,說明以下幾點:關于虛函數,說明以下幾點:1、當在基類中把成員函數定義為虛函數后,當在基類中把成員函數定義為虛函數后,在其派生類中定義的虛函數必須與基類中的在其派生類中定義的虛函數必須與基類中的虛函數同名,參數的類型、順序、參數的個虛函數同名,參數的類型、

24、順序、參數的個數必須一一對應,函數的返回的類型也相同數必須一一對應,函數的返回的類型也相同。若函數名相同,但參數的個數不同或者參數若函數名相同,但參數的個數不同或者參數的類型不同時,則屬于函數的重載,而不是的類型不同時,則屬于函數的重載,而不是虛函數。若函數名不同,顯然這是不同的成虛函數。若函數名不同,顯然這是不同的成員函數。員函數。292、實現這種動態(tài)的多態(tài)性時,必須使用實現這種動態(tài)的多態(tài)性時,必須使用基類類型基類類型的指針變量的指針變量,并使該指針,并使該指針指向不同的派生類對象指向不同的派生類對象,并通過調用指針所指向的虛函數才能實現動態(tài)的并通過調用指針所指向的虛函數才能實現動態(tài)的多態(tài)性

25、。多態(tài)性。xShow()xShow()yShow()xShow()zShow()類類A類類B類類CShow()定義為虛函數定義為虛函數類類B與類與類C均為類均為類A的公有派生。的公有派生。A *p; B b;C c; p=&b ; p-Show();p=&c ; p-Show();即在程序運行時,即在程序運行時,通過賦值語句實通過賦值語句實現多態(tài)性現多態(tài)性303、虛函數必須是類的一個成員函數,不能是虛函數必須是類的一個成員函數,不能是友元函數,也不能是靜態(tài)的成員函數。友元函數,也不能是靜態(tài)的成員函數。4、在派生類中、在派生類中沒有重新定義虛函數沒有重新定義虛函數時,與一時,與一

26、般的成員函數一樣,當調用這種派生類對象般的成員函數一樣,當調用這種派生類對象的虛函數時,的虛函數時,則調用其基類中的虛函數則調用其基類中的虛函數。5、可把析構函數定義為虛函數,但是,不能可把析構函數定義為虛函數,但是,不能將構造函數定義為虛函數將構造函數定義為虛函數。316、虛函數與一般的成員函數相比較,、虛函數與一般的成員函數相比較,調用時的執(zhí)調用時的執(zhí)行速度要慢一些行速度要慢一些。為了實現多態(tài)性,在每一個派。為了實現多態(tài)性,在每一個派生類中均要保存相應虛函數的入口地址表,函數生類中均要保存相應虛函數的入口地址表,函數的調用機制也是間接實現的。因此,除了要編寫的調用機制也是間接實現的。因此,

27、除了要編寫一些通用的程序,并一定要使用虛函數才能完成一些通用的程序,并一定要使用虛函數才能完成其功能要求外,通常不必使用虛函數。其功能要求外,通常不必使用虛函數。7、一個函數如果被定義成虛函數,則不管經歷多、一個函數如果被定義成虛函數,則不管經歷多少次派生,仍將保持其虛特性,以實現少次派生,仍將保持其虛特性,以實現“一個接一個接口,多個形態(tài)口,多個形態(tài)”。32虛函數的訪問虛函數的訪問用基指針訪問與用對象名訪問用基指針訪問與用對象名訪問用基指針訪問虛函數時,指向其實際派生類用基指針訪問虛函數時,指向其實際派生類對象重新定義的函數。實現動態(tài)聚束。對象重新定義的函數。實現動態(tài)聚束。通過一個通過一個對

28、象名對象名訪問時,只能靜態(tài)聚束。即訪問時,只能靜態(tài)聚束。即由編譯器在編譯的時候決定調用哪個函數。由編譯器在編譯的時候決定調用哪個函數。33class Point float x,y;public: Point()Point(float i,float j)x=i;y=j;virtual float area(void) return 0.0; /聲明為虛函數聲明為虛函數;const float Pi=3.14159;class Circle:public Point/類類Point的派生類的派生類float radius;public: Circle(float r)radius=r;floa

29、t area(void) return Pi*radius*radius;/虛函數再定義虛函數再定義;void main(void) Point *pp; /基類指針,可以將派生類對象的地址賦給基類指針基類指針,可以將派生類對象的地址賦給基類指針 Circle c(5.4321); coutc.area()endl; coutc.Point:area()endl; coutc.Circle:area ()endl;輸出:輸出:92.7011092.7011可見,利用對象名進行調用與一般非虛函數沒有區(qū)別??梢?,利用對象名進行調用與一般非虛函數沒有區(qū)別。用對象名調用用對象名調用area( )34c

30、lass base0public: void v(void)coutbase0n;class base1:public base0public: virtual void v(void) coutbase1n; ;class A1:public base1public: void v()coutA1n; ;class A2:public A1public: void v(void)coutA2n; ;class B1:private base1public: void v(void)coutB1n; ;class B2:public B1public: void v(void)coutv();

31、 A2 a2; (pb=&a2)-v(); B1 b1; (pb=&b1)-v(); B2 b2; (pb=&b2)-v();base0base0私有派生,在類外私有派生,在類外不能調用基類函數不能調用基類函數35class base0public: void v(void)coutbase0n;class base1:public base0public: virtual void v(void) coutbase1n; ;class A1:public base1public: void v()coutA1n; ;class A2:public A1public:

32、void v(void)coutA2n; ;class B1:private base1public: void v(void)coutB1n; ;class B2:public B1public: void v(void)coutv(); A2 a2; (pb=&a2)-v();A1A236純虛函數純虛函數在基類中不對虛函數給出有意義的實現在基類中不對虛函數給出有意義的實現,它只是它只是在派生類中有具體的意義。這時基類中的虛函數在派生類中有具體的意義。這時基類中的虛函數只是一個入口,具體的目的地由不同的派生類中只是一個入口,具體的目的地由不同的派生類中的對象決定。這個虛函數稱為的對象

33、決定。這個虛函數稱為純虛函數純虛函數。class virtual ()=0;.;37class Aprotected:int x;public: A()x =1000; virtual void print()=0; /定義純虛函數定義純虛函數;class B:public A /派生類派生類private: int y;public: B() y=2000;void print()cout “y=”yn;/重新定義純虛函數重新定義純虛函數;class C:public A /派生類派生類int z;public: C()z=3000;void print()cout “z=”zprint()

34、; pa=&c; pa-print(); A a; pa=&a; pa-print( );y=2000z=3000抽象類抽象類不能定義抽象類的對象不能定義抽象類的對象381、在定義純虛函數時,不能定義虛函數的實、在定義純虛函數時,不能定義虛函數的實現部分?,F部分。2、把函數名賦于、把函數名賦于0,本質上是將指向函數體,本質上是將指向函數體的指針值賦為初值的指針值賦為初值0。與定義空函數不一樣,。與定義空函數不一樣,空函數的函數體為空,即調用該函數時,不空函數的函數體為空,即調用該函數時,不執(zhí)行任何動作。執(zhí)行任何動作。在沒有重新定義這種純虛函在沒有重新定義這種純虛函數之前,是不能

35、調用這種函數的。數之前,是不能調用這種函數的。393、把至少包含一個純虛函數的類,稱為抽象把至少包含一個純虛函數的類,稱為抽象類。這種類只能作為派生類的基類,不能用類。這種類只能作為派生類的基類,不能用來說明這種類的對象來說明這種類的對象。其理由是明顯的:因為虛函數沒有實現部分,其理由是明顯的:因為虛函數沒有實現部分,所以不能產生對象。但可以定義指向抽象類所以不能產生對象。但可以定義指向抽象類的指針,即指向這種基類的指針。當用這種的指針,即指向這種基類的指針。當用這種基類指針指向其派生類的對象時,基類指針指向其派生類的對象時,必須在派必須在派生類中生類中重載重載純虛函數,否則會產生程序的運純虛

36、函數,否則會產生程序的運行錯誤。行錯誤。404、在以抽象類作為基類的派生類中必須有在以抽象類作為基類的派生類中必須有純虛函數的實現部分,即必須有重載純虛函純虛函數的實現部分,即必須有重載純虛函數的函數體。否則,這樣的派生類也是不能數的函數體。否則,這樣的派生類也是不能產生對象的。產生對象的。綜上所述,可把純虛函數歸結為:綜上所述,可把純虛函數歸結為:抽象類的抽象類的唯一用途是為派生類提供基類,純虛函數的唯一用途是為派生類提供基類,純虛函數的作用是作為派生類中的成員函數的基礎,并作用是作為派生類中的成員函數的基礎,并實現動態(tài)多態(tài)性。實現動態(tài)多態(tài)性。41虛基類虛基類多基派生中的多條路徑具有公共基類

37、時,在這條路徑的匯合處就會多基派生中的多條路徑具有公共基類時,在這條路徑的匯合處就會因對公共基類產生多個拷貝而產生同名函數調用的二義性。因對公共基類產生多個拷貝而產生同名函數調用的二義性。解決這個問題的辦法就是把解決這個問題的辦法就是把公共基類定義為虛基類公共基類定義為虛基類,使由它派生的,使由它派生的多條路徑的匯聚處只產生一個拷貝。多條路徑的匯聚處只產生一個拷貝。class Base ;class A : public Base ;class B: public Base ;class C: public A, public B ;類類C中繼承了兩個類中繼承了兩個類Base,即有兩個類即有兩

38、個類Base的實現部分,的實現部分,在調用時產生了二義性。在調用時產生了二義性。42用虛基類進行多重派生時,用虛基類進行多重派生時,若虛基類沒有缺若虛基類沒有缺省的構造函數省的構造函數,則在每一個派生類的構造函,則在每一個派生類的構造函數中數中都必須有對虛基類構造函數的調用都必須有對虛基類構造函數的調用 (且(且首先調用)。首先調用)。由虛基類派生出的對象初始化時,由虛基類派生出的對象初始化時,直接調用直接調用虛基類的構造函數。因此,若將一個類定義虛基類的構造函數。因此,若將一個類定義為虛基類,則一定有正確的構造函數可供所為虛基類,則一定有正確的構造函數可供所有派生類調用。有派生類調用。43c

39、lass basepublic:virtual void a() couta() in basen;virtual void b() coutb() in basen;virtual void c() coutc() in basen;virtual void d() coutd() in basen;virtual void e() coute() in basen;virtual void f() coutf() in basen;class A:public basepublic:virtual void a() couta() in An;virtual void b() coutb(

40、) in An;virtual void f() coutf() in An;class B:public basepublic:virtual void a() couta() in Bn;virtual void b() coutb() in Bn;virtual void c() coutc() in Bn;class C:public A,public Bpublic:virtual void a() couta() in Cn;virtual void d() couta(); pa-b(); pa-c(); pa-d(); pa-e(); pa-f();將類將類C的地址賦的地址賦值

41、時產生歧義值時產生歧義44a( )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( )AB45class basepublic:virtual void a() couta() in basen;virtual void b() coutb() in basen;virtual void c() coutc(

42、) in basen;virtual void d() coutd() in basen;virtual void e() coute() in basen;virtual void f() coutf() in basen;class A:public basepublic:virtual void a() couta() in An;virtual void b() coutb() in An;virtual void f() coutf() in An;class B:public basepublic:virtual void a() couta() in Bn;virtual voi

43、d b() coutb() in Bn;virtual void c() coutc() in Bn;class C:public A,public Bpublic:virtual void a() couta() in Cn;virtual void d() couta(); pa-b(); pa-c(); pa-d(); pa-e(); pa-f();將類將類C的地址賦的地址賦值時產生歧義值時產生歧義類類C中有兩個中有兩個base,只有一個,只有一個Aa() in Cb() in Ac() in based() in Ce() in basef() in A為避免這種情況,將為避免這種情況

44、,將base定義定義為虛基類。為虛基類。46class basepublic:virtual void a() couta() in basen;virtual void b() coutb() in basen;virtual void c() coutc() in basen;virtual void d() coutd() in basen;virtual void e() coute() in basen;virtual void f() coutf() in basen;class A:virtual public basepublic:virtual void a() couta(

45、) in An;virtual void b() coutb() in An;virtual void f() coutf() in An;class B:virtual public basepublic:virtual void a() couta() in Bn;virtual void c() coutc() in Bn;class C:public A,public Bpublic:virtual void a() couta() in Cn;virtual void d() couta(); pa-b(); pa-c(); pa-d(); pa-e(); pa-f();47a( )

46、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( )AB48class basepublic:virtual void a() couta() in basen;virtual void b() coutb() in basen;virtual void c() coutc() in basen;virtual void d() coutd() in ba

47、sen;virtual void e() coute() in basen;virtual void f() coutf() in basen;class A:virtual public basepublic:virtual void a() couta() in An;virtual void b() coutb() in An;virtual void f() coutf() in An;class B:virtual public basepublic:virtual void a() couta() in Bn;virtual void c() coutc() in Bn;class

48、 C:public A,public Bpublic:virtual void a() couta() in Cn;virtual void d() couta(); pa-b(); pa-c(); pa-d(); pa-e(); pa-f();類類C中只有一個中只有一個basea() in Cb() in Ac() in Bd() in Ce() in basef() in A49class basepublic:void a()couta() in basen;void b()coutb() in basen;void c()coutc() in basen;void d()coutd()

49、 in basen;void e()coute() in basen;void f()coutf() in basen;class A:virtual public basepublic:void a()couta() in An;void b()coutb() in An;void f()coutf() in An;class B:virtual public basepublic:void a()couta() in Bn;void c()coutc() in Bn;class C:public A,public Bpublic:void a()couta() in Cn;void d()

50、couta(); pa-b(); pa-c(); pa-d(); pa-e(); pa-f();類類C中只有一個中只有一個basea() in baseb() in basec() in based() in basee() in basef() in base50下面程序的輸出是下面程序的輸出是 。class Aprotected:int x;public:A()x =1000;virtual void p()cout x=xn; p2(); virtual void p2()coutA:p2()endl; ;class C:public Aint z;public:C()z=3000; v

51、oid p()cout z=zn; p2();virtual void p2()coutC:p2()p();pa=&c;pa-p();51 通常,每當說明一個對象時,把該類中的有關成員通常,每當說明一個對象時,把該類中的有關成員數據拷貝到該對象中,即同一類的不同對象,數據拷貝到該對象中,即同一類的不同對象,其成員數據其成員數據之間是互相獨立的之間是互相獨立的。靜態(tài)成員靜態(tài)成員 class A int x,y; public: void Setxy(int a, int b) x=a; y=b;A a1, a2;a1.xa1.ya2.xa2.y.x=a ;y=b ;.a1. Setxy(

52、)a2. Setxy()a1.Setxy(1,2);a2.Setxy(3,4);this-x=a;this-y=b;52當我們將類的某一個當我們將類的某一個數據成員的存儲類型指定為靜態(tài)類型數據成員的存儲類型指定為靜態(tài)類型時時,則由該類所產生的所有對象,其靜態(tài)成員均共享,則由該類所產生的所有對象,其靜態(tài)成員均共享一個一個存儲空間存儲空間,這個空間是在編譯的時候分配的這個空間是在編譯的時候分配的。換言之,在。換言之,在說明對象時,并不為靜態(tài)類型的成員分配空間。說明對象時,并不為靜態(tài)類型的成員分配空間。 在類定義中,用關鍵字在類定義中,用關鍵字static修飾的數據成員稱為靜修飾的數據成員稱為靜態(tài)數

53、據成員。態(tài)數據成員。class A int x,y; static int z; public: void Setxy(int a, int b) x=a; y=b;A a1, a2;a1.xa1.ya2.xa2.yza1. za2. z不同對象,同一空間不同對象,同一空間53有關靜態(tài)數據成員的使用,說明以下幾點:有關靜態(tài)數據成員的使用,說明以下幾點:1、類的靜態(tài)數據成員是、類的靜態(tài)數據成員是靜態(tài)分配存儲空間靜態(tài)分配存儲空間的,而其它成員是動態(tài)分配存儲空間的(全的,而其它成員是動態(tài)分配存儲空間的(全局變量除外)。當類中沒有定義靜態(tài)數據成局變量除外)。當類中沒有定義靜態(tài)數據成員時,在程序執(zhí)行期間

54、遇到說明類的對象時,員時,在程序執(zhí)行期間遇到說明類的對象時,才為對象的所有成員依次分配存儲空間,這才為對象的所有成員依次分配存儲空間,這種存儲空間的分配是動態(tài)的;種存儲空間的分配是動態(tài)的;而當類中定義而當類中定義了靜態(tài)數據成員時,了靜態(tài)數據成員時,在編譯時,就要為類的在編譯時,就要為類的靜態(tài)數據成員分配存儲空間靜態(tài)數據成員分配存儲空間。542、必須在文件作用域中,對靜態(tài)數據成員作必須在文件作用域中,對靜態(tài)數據成員作一次且只能作一次定義性說明一次且只能作一次定義性說明。因為靜態(tài)數。因為靜態(tài)數據成員在定義性說明時已分配了存儲空間,據成員在定義性說明時已分配了存儲空間,所以通過靜態(tài)數據成員名前加上所

55、以通過靜態(tài)數據成員名前加上類名和作用類名和作用域運算符域運算符,可直接引用靜態(tài)數據成員。在,可直接引用靜態(tài)數據成員。在C+中,靜態(tài)變量缺省的初值為中,靜態(tài)變量缺省的初值為0,所以靜態(tài),所以靜態(tài)數據成員總有唯一的初值。當然,數據成員總有唯一的初值。當然,在對靜態(tài)在對靜態(tài)數據成員作定義性的說明時,數據成員作定義性的說明時,也可以指定一也可以指定一個初值。個初值。55class Aint i,j;static int x,y;/定義靜態(tài)成員定義靜態(tài)成員public: A(int a=0,int b=0,int c=0, int d=0)i=a;j=b;x=c;y=d;void Show()cout

56、i=itj=jt; cout x=xty=yn; ;int A:x=0; /必須對靜態(tài)成員作一次定義性說明必須對靜態(tài)成員作一次定義性說明 int A:y=0; void main(void )A a(2,3,4,5);a.Show();A b(100,200,300,400);b.Show();a.Show();a.x 和和b.x在內存中占據一個空間在內存中占據一個空間a.y 和和b.y在內存中占據一個空間在內存中占據一個空間i=2j=3x=4y=5i=100 j=200 x=300 y=400i=2j=3x=300 y=40056class Aint i,j;public: static i

57、nt x;public: A(int a=0,int b=0,int c=0) i=a ; j=b ; x=c; void Show()cout i=itj=jt;cout x=xn;int A:x=500; /int A:xvoid main(void )A a(20,40,10),b(30,50,100);a.Show ();b.Show ();cout “A:x=”A:xn; /可以直接用類名引用可以直接用類名引用在類外重新定義在類外重新定義573、靜態(tài)數據成員具有全局變量和局部變量的一些、靜態(tài)數據成員具有全局變量和局部變量的一些特性。靜態(tài)數據成員與全局變量一樣都是靜態(tài)分特性。靜態(tài)數據成

58、員與全局變量一樣都是靜態(tài)分配存儲空間的,配存儲空間的,但全局變量在程序中的任何位置但全局變量在程序中的任何位置都可以訪問它,而靜態(tài)數據成員受到訪問權限的都可以訪問它,而靜態(tài)數據成員受到訪問權限的約束。約束。必須是必須是public權限時,才可能在類外進行訪權限時,才可能在類外進行訪問問。4、為了保持靜態(tài)數據成員取值的一致性,通常在、為了保持靜態(tài)數據成員取值的一致性,通常在構造函數中不給靜態(tài)數據成員置初值,構造函數中不給靜態(tài)數據成員置初值,而是在對而是在對靜態(tài)數據成員的定義性說明時指定初值靜態(tài)數據成員的定義性說明時指定初值。 58class Aint i;static int count;pub

59、lic:A(int a=0) i=a; count+; cout Number of Objects=countn; A() count-; cout Number of Objects=countn; void Show() cout i=in; cout count=countn;int A:count;void main(void )A a1(100);A b2;a1.Show();Number of Objects=1Number of Objects=2Number of Objects=3i=100count=3Number of Objects=2Number of Object

60、s=1Number of Objects=059靜態(tài)成員函數靜態(tài)成員函數可以將類的成員函數定義為靜態(tài)的成員函數。即可以將類的成員函數定義為靜態(tài)的成員函數。即使用關鍵字使用關鍵字static來修飾成員函數來修飾成員函數 。class A float x, y;public : A( ) static void sum(void) . ;60對靜態(tài)成員函數的用法說明以下幾點:對靜態(tài)成員函數的用法說明以下幾點:1、與靜態(tài)數據成員一樣,在類外的程序代碼中,與靜態(tài)數據成員一樣,在類外的程序代碼中,通過類名加上作用域操作符,可直接調用靜態(tài)成通過類名加上作用域操作符,可直接調用靜態(tài)成員函數員函數。 2、靜態(tài)成員函數只能直接使用本類的靜態(tài)數據成靜態(tài)成員函數只能直接使用本類的靜態(tài)數據成員或靜態(tài)成員函數員或靜態(tài)成員函數,但不能直接使用非靜態(tài)的數但不能直接使用非靜態(tài)的數據成員據成員 (可以引用使用)。這是因為靜態(tài)成員函(

溫馨提示

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

評論

0/150

提交評論