版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、第六章第六章 多態(tài)性多態(tài)性語文、數(shù)學(xué)、英語、政治、語文、數(shù)學(xué)、英語、政治、物理、化學(xué)、生物物理、化學(xué)、生物多態(tài)性指,同一個消息被不同對象接收時,多態(tài)性指,同一個消息被不同對象接收時,產(chǎn)生不同結(jié)果,即實現(xiàn)同一接口,不同方法。產(chǎn)生不同結(jié)果,即實現(xiàn)同一接口,不同方法。高中生計計 算算平均成績平均成績多態(tài)性多態(tài)性多態(tài)性指,同一個消息被不同對象接收時,多態(tài)性指,同一個消息被不同對象接收時,產(chǎn)生不同結(jié)果,即實現(xiàn)同一接口,不同方法。產(chǎn)生不同結(jié)果,即實現(xiàn)同一接口,不同方法。計計 算算平均成績平均成績大學(xué)生高數(shù)、英語、計算機(jī)、高數(shù)、英語、計算機(jī)、線性代數(shù)線性代數(shù)多態(tài)性多態(tài)性多態(tài) 重載多態(tài):通過調(diào)用相同名字的函數(shù)
2、,表現(xiàn)出不同的行為。運算符重載也是一種重載多態(tài)。 運行多態(tài):通過基類的指針,調(diào)用不同派生類的同名函數(shù),表現(xiàn)出不同的行為。許多面向?qū)ο蟪绦蛟O(shè)計的書籍中所說的多態(tài)性,就是這種多態(tài)。 模板多態(tài),也稱為參數(shù)多態(tài):通過一個模板,得到不同的函數(shù)或不同的類。這些函數(shù)或者類具有不同的特性和不同的行為。 第六章 多態(tài)性 多態(tài)與虛函數(shù) 虛函數(shù)(安全編程:覆蓋C+虛函數(shù)指針) 純虛函數(shù)和抽象類 運算符重載 模板 函數(shù)模板 類模板本章要求 理解多態(tài)性的概念 掌握虛函數(shù)的原理及使用 掌握運算符重載 掌握模板程序設(shè)計第六章 多態(tài)性多態(tài)與虛函數(shù)多態(tài)與虛函數(shù) 虛函數(shù)(安全編程:覆蓋C+虛函數(shù)指針) 純虛函數(shù)和抽象類 運算符重
3、載 模板 函數(shù)模板 類模板實例幾何形狀幾何形狀橢圓橢圓圓圓三角形三角形矩形矩形正方形正方形6.1 多態(tài)與虛函數(shù) 賦值兼容規(guī)則(子類型):需要基類對象的任何地方都可以使用公有派生類的對象來替代. 替代包括: 派生類的對象可以賦值給基類對象. 派生類的對象可以初始化基類的引用. 派生類的地址可以賦給指向基類的指針.A a,*p;B b;A &g=b;a=b;P=&b;class A public: void f(); void g();class B:public A public: void h(); 虛函數(shù) 虛函數(shù)是成員函數(shù)而且是非static的成員函數(shù)。說明虛函數(shù)的方法如下:
4、 virtual 類型說明 函數(shù)說明(參數(shù)表) 一旦在基類中指定某成員為虛函數(shù),那么不管在派生類中是否給出virtual聲明,派生類(以及派生類的派生類,依次類推)中對其重定義的成員函數(shù)均為虛函數(shù)。虛函數(shù) 重定義指對派生類中定義的成員函數(shù),其重定義指對派生類中定義的成員函數(shù),其函數(shù)名、參數(shù)個數(shù)和類型以及返回值類型函數(shù)名、參數(shù)個數(shù)和類型以及返回值類型與基類的虛成員函數(shù)相同。與基類的虛成員函數(shù)相同。(當(dāng)基類虛函數(shù)返回值類型是某個類或其指針或引用時,派生類中重定義的成員函數(shù)的返回值也可以是子類型,vc+6.0不支持)。靜態(tài)聯(lián)編和動態(tài)聯(lián)編 聯(lián)編:將一個函數(shù)的調(diào)用與相應(yīng)的函數(shù)體的代碼相連接稱為函數(shù)聯(lián)編。
5、 靜態(tài)聯(lián)編:在編譯根據(jù)CShape* pShape6的靜態(tài)類型類決定pShapei-display()屬于哪一個類。由于pShapei 的靜態(tài)類型是CShape* ,所以確定display()是CShape: display. 動態(tài)聯(lián)編:在運行時,根據(jù)pShapei實際指向的對象類型來確定display()屬于哪一個類。C+規(guī)定動態(tài)聯(lián)編是在虛函數(shù)的支持下實現(xiàn)的。o 使用虛函數(shù)的注意事項使用虛函數(shù)的注意事項n 只有類的成員函數(shù)才能說明為虛函數(shù)只有類的成員函數(shù)才能說明為虛函數(shù)n 靜態(tài)成員函數(shù)不能是虛函數(shù)靜態(tài)成員函數(shù)不能是虛函數(shù)n 內(nèi)聯(lián)內(nèi)聯(lián)(inline)函數(shù)不能是虛函數(shù)函數(shù)不能是虛函數(shù)n 構(gòu)造函數(shù)
6、不能是虛函數(shù)構(gòu)造函數(shù)不能是虛函數(shù)n 析構(gòu)函數(shù)可以是虛函數(shù)析構(gòu)函數(shù)可以是虛函數(shù),而且通常聲明為虛而且通常聲明為虛函數(shù)函數(shù)參見工程參見工程0106虛函數(shù)虛析構(gòu)函數(shù) 如果用動態(tài)創(chuàng)建的派生類對象的地址初始化基類的指針,創(chuàng)建的過程不會有問題:仍然是先調(diào)用基類構(gòu)造函數(shù),再執(zhí)行派生類構(gòu)造函數(shù)。 但是,在用delete運算符刪除這個指針的時候,由于指針是指向基類的,通過靜態(tài)聯(lián)編,只會調(diào)用基類的析構(gòu)函數(shù)。 為了解決派生類對象釋放不徹底的問題,必須將基類的析構(gòu)函數(shù)定義為虛析構(gòu)函數(shù)。格式是在析構(gòu)函數(shù)的名字前添加virtual關(guān)鍵字。函數(shù)原型如下:virtual CShape(); 此時,無論派生類析構(gòu)函數(shù)是不是用v
7、irtual來說明,也都是虛析構(gòu)函數(shù)。 再用delete shape來釋放基類指針時,就會通過動態(tài)聯(lián)編調(diào)用派生類的析構(gòu)函數(shù)。虛析構(gòu)函數(shù)深入理解多態(tài)性o 什么是多態(tài)性什么是多態(tài)性n 不同對象收到相同消息時產(chǎn)生不同的動作不同對象收到相同消息時產(chǎn)生不同的動作n 多態(tài)性的實現(xiàn)與函數(shù)聯(lián)編有關(guān)多態(tài)性的實現(xiàn)與函數(shù)聯(lián)編有關(guān)o 將一個函數(shù)的調(diào)用與相應(yīng)的函數(shù)體的代碼將一個函數(shù)的調(diào)用與相應(yīng)的函數(shù)體的代碼相連接稱為函數(shù)聯(lián)編相連接稱為函數(shù)聯(lián)編深入理解多態(tài)性o 編譯時的多態(tài)性編譯時的多態(tài)性n 靜態(tài)聯(lián)編所支持的多態(tài)性稱為編譯時的多態(tài)靜態(tài)聯(lián)編所支持的多態(tài)性稱為編譯時的多態(tài)性性n 函數(shù)重載、運算符重載、參數(shù)多態(tài)函數(shù)重載、運算符
8、重載、參數(shù)多態(tài)o 運行時的多態(tài)性運行時的多態(tài)性n 動態(tài)聯(lián)編所支持的多態(tài)性稱為運行時的多態(tài)動態(tài)聯(lián)編所支持的多態(tài)性稱為運行時的多態(tài)性性n 通過虛函數(shù)的繼承實現(xiàn)通過虛函數(shù)的繼承實現(xiàn)void 叫某人來吃飯(人叫某人來吃飯(人 p) p.吃飯();吃飯();深入理解多態(tài)性 應(yīng)用程序不必為每個派生類編寫功能調(diào)用,只要對基類進(jìn)行處理即可以不變應(yīng)萬變,可以大大提高程序的可復(fù)用性。深入理解多態(tài)性class Employee virtual int GetSalary()=0;class sales:public Employee public: int GetSalary()/顯示工資程序Employee *p
9、e = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary() 應(yīng)用程序不必為每個派生類編寫功能調(diào)用,只要對基類進(jìn)行處理即可以不變應(yīng)萬變,可以大大提高程序的可復(fù)用性。 派生類的功能可以被基類的方法,指針或引用調(diào)用,這叫向后兼容,可以提高程序的擴(kuò)充性和可維護(hù)性。深入理解多態(tài)性class Employee virtual int GetSalary()=0;class sales:public Employee public: int GetSalary()/顯示
10、工資程序Employee *pe = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary()運行時的多態(tài)性需要滿足三個條件:運行時的多態(tài)性需要滿足三個條件:首先,類之間應(yīng)該滿足賦值兼容規(guī)則。首先,類之間應(yīng)該滿足賦值兼容規(guī)則。其二,要聲明虛函數(shù)。其二,要聲明虛函數(shù)。第三,要由第三,要由成員函數(shù)成員函數(shù)來調(diào)用或者通過來調(diào)用或者通過指針指針、引用引用來訪問虛函數(shù)。來訪問虛函數(shù)。如果使用對象名來訪問虛函數(shù),則聯(lián)編在編如果使用對象名來訪問虛函數(shù),則聯(lián)編在編譯過程中就可以
11、進(jìn)行,而無需在運行過程中譯過程中就可以進(jìn)行,而無需在運行過程中進(jìn)行。進(jìn)行。class Apublic: A() f(); A() virtual void f(); void g(); void h()f();g();class B:public Apublic: B() void f(); void g();A a;a.f();a.g();a.h();B b;b.f();b.g();b.h();A:A()和和A:fA:fA:gA:h ,A:f ,A:gB:B() ,A:A() ,A:fB:fB:gA:h ,B:f ,A:gclass Apublic: A() f(); A() virtual
12、 void f(); void g(); void h()f();g();class B:public Apublic: B() void f(); void g();A *p; A a;p=&a;p-f();p-g();p-h();A:fA:gA:h ,A:f ,A:gclass Apublic: A() f(); A() virtual void f(); void g(); void h()f();g();class B:public Apublic: B() void f(); void g();A *p; p=&b;p-f();p-A:f();p-g();p-h();
13、B:fA:fA:gA:h ,B:f ,A:gclass Apublic: A() f(); A() virtual void f(); void g(); void h()f();g();class B:public Apublic: B() void f(); void g();A *p; p=new B;delete p;B:B() ,A:A() ,A:fA:A() 基類構(gòu)造函數(shù)中對虛函數(shù)的調(diào)用不采用動態(tài)基類構(gòu)造函數(shù)中對虛函數(shù)的調(diào)用不采用動態(tài)綁定。綁定。注意class Employee virtual int GetSalary()=0;class sales:public Employe
14、e public: int GetSalary()/顯示工資程序Employee *pe = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary()純虛函數(shù)和抽象類 什么是純虛函數(shù) 純虛函數(shù)只有函數(shù)的聲明,函數(shù)的定義必須在其派生類中完成 聲明純虛函數(shù)的類不能實例化 什么是抽象類 聲明有純虛函數(shù)的類稱為抽象類 純虛函數(shù)的聲明virtual 返回值類型返回值類型 函數(shù)名函數(shù)名() = 0;參見工程參見工程0108class Employee virtual int
15、 GetSalary()=0;class sales:public Employee public: int GetSalary()/顯示工資程序Employee *pe = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary() 抽象類的主要作用是通過它為一個類族建立一個公共的接口,使他們能夠更有效的發(fā)揮多態(tài)特性。純虛函數(shù)和抽象類class Employee virtual int GetSalary()=0;class sales:public Emplo
16、yee public: int GetSalary()/顯示工資程序Employee *pe = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary() 抽象類的主要作用是通過它為一個類族建立一個公共的接口,使他們能夠更有效的發(fā)揮多態(tài)特性。 抽象類派生出新類后,如果派生類沒有給出全部純虛函數(shù)的實現(xiàn),這時的派生類仍然是一個抽象類。 抽象類不能實例化,但可以聲明一個抽象類的指針和引用。通過指針或引用,我們就可以指向并訪問派生類對象,進(jìn)而訪問派生類的成員,這種訪問是
17、具有多態(tài)特征的。純虛函數(shù)和抽象類class Employee virtual int GetSalary()=0;class sales:public Employee public: int GetSalary()/顯示工資程序Employee *pe = emFactory.GetEmployee(id);pe-GetSalary();class engineer:public Employee public: int GetSalary()class B0public: virtual void display()=0;class B1:public B0public: void dis
18、play()cout“B1:display”;class D1:public B1public: void display()coutdisplay();void main()B0 *p; B1 b1; D1 d1; p=&b1;fun(p);/B1:display p=&d1;fun(p);/D1:display關(guān)于純虛函數(shù)和抽象類的描述中,( )是錯誤的。A. 純虛函數(shù)是一種特殊的虛函數(shù),它沒有具體的實現(xiàn)。B. 抽象類是指具有純虛函數(shù)的類。C. 一個基類中說明有純虛函數(shù),該基類的派生類一定不再是抽象類。D. 抽象類只能作為基類來使用,其純虛函數(shù)的實現(xiàn)由派生類給出。練習(xí)第六章
19、 多態(tài)性 多態(tài)與虛函數(shù) 虛函數(shù)(安全編程:覆蓋C+虛函數(shù)指針) 純虛函數(shù)和抽象類運算符重載運算符重載 模板 函數(shù)模板 類模板6.2 運算符重載 例:實現(xiàn)復(fù)數(shù)的表示及其加法操作。 C+語言沒有提供復(fù)數(shù)類型。為了使程序中能夠表示和處理復(fù)數(shù),我們用一個復(fù)數(shù)類來實現(xiàn)它。 為了能實現(xiàn)復(fù)數(shù)加法操作,可以在復(fù)數(shù)類的定義中定義一個成員函數(shù)add,它把調(diào)用它的復(fù)數(shù)對象和參數(shù)指定的復(fù)數(shù)對象相加,返回相加之后得到的復(fù)數(shù)對象。class Complex double real,imag; public: Complex()real=0;imag=0; Complex(double r,double i)real=r;
20、imag=i; Complex add(const Complex &x) const Complex temp; temp.real=real+x.real; temp.imag=imag+x.imag; return temp; ;Complex a(1,2),b(3,4),c;c=a.add(b);Complex a(1,2),b(3,4),c;c=a+b;class Complex double real,imag; public: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i;Complex
21、operator + (const Complex &x) const Complex temp; temp.real=real+x.real; temp.imag=imag+x.imag; return temp; ;Complex a(1,2),b(3,4),c;c=a+b;class Complexdouble real,imag; public: ;Complex add (const Complex &c1, const Complex &c2)Complex temp; temp.real=c1.real+c2.real; temp.imag=c1.imag
22、+c2.imag; return temp;friend Complex add (const Complex &c1, const Complex &c2)Complex a(1,2),b(3,4),c;c=add(a,b);class Complexdouble real,imag; public: ;Complex operator + (const Complex &c1, const Complex &c2)Complex temp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; retur
23、n temp;friend Complex operator + (const Complex &c1, const Complex &c2)Complex a(1,2),b(3,4),c;c=a+b;運算符重載 重載為類成員函數(shù)。 重載為全局(友元)函數(shù)。重載的兩種形式性能提示:可以把一個運算符作為一個非成員、非友元函數(shù)重載。但是,這樣的運算符函數(shù)訪問類的private和protected數(shù)據(jù)時必須使用類的public接口中提供的函數(shù),調(diào)用這些函數(shù)所涉及的開銷會降低性能。可以將這些函數(shù)內(nèi)聯(lián)以提高性能。class Complex double real,imag; public
24、: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i;Complex operator + (const Complex &x) const Complex temp; temp.real=real+x.real; temp.imag=imag+x.imag; return temp; ;class Complexdouble real,imag; public: ;Complex operator + (const Complex &c1, const Complex &c2)Comple
25、x temp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; return temp;friend Complex operator + (const Complex &c1, const Complex &c2) 定義形式函數(shù)類型函數(shù)類型 operator 運算符(形參)運算符(形參) . 重載為類成員函數(shù)時 參數(shù)個數(shù)=原操作數(shù)個數(shù)-1(后置+、-除外) 重載為全局(友元)函數(shù)時 參數(shù)個數(shù)=原操作數(shù)個數(shù)(后置+、-除外),且至少應(yīng)該有一個自定義類型的形參。重載的兩種形式作為成員函數(shù)重載 雙目操作符重載函數(shù)的聲明格式
26、class operator #(); 雙目操作符重載函數(shù)的定義格式 :operator #()class Complex double real,imag; public: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i;Complex operator + (const Complex &x) const Complex temp; temp.real=real+x.real; temp.imag=imag+x.imag; return temp; ; 雙目操作符重載函數(shù)的使用格式 a; b;a#b;
27、或或a.operator#(b);作為成員函數(shù)重載class Complex double real,imag; public: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i;Complex operator + (const Complex &x) const Complex temp; temp.real=real+x.real; temp.imag=imag+x.imag; return temp; ; 單目操作符重載函數(shù)的聲明格式class operator #(); 單目操作符重載函數(shù)的定義格
28、式 :operator #()作為成員函數(shù)重載 單目操作符重載函數(shù)的使用格式 a;#a;或a.operator#(); 對于單目操作符,其重載函數(shù)是單目操作符的前置用法。而操作符+和有前置和后置兩種用法。為了能夠區(qū)分,則可以定義另一個帶有int型參數(shù)的操作符+和的重載函數(shù)來表示它們的后置用法。作為成員函數(shù)重載int fun() static int a=4; return a;int& fun() static int a=4; return a; A fun() static A a; return a;A& fun() static A a; return a;class
29、A ;constclass Counter int value; public: Counter()value=0; Counter& operator +() /前置前置 value+; return *this; const Counter operator +(int) /后置后置 Counter temp=*this; +(*this); return temp;;作為全局(友元)函數(shù)重載 雙目操作符重載函數(shù)的定義格式 operator #( , ) class Complexdouble real,imag; public: ;Complex operator + (cons
30、t Complex &c1, const Complex &c2)Complex temp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; return temp;friend Complex operator + (const Complex &c1, const Complex &c2)作為全局(友元)函數(shù)重載 使用格式 a; b;a#b或operator#(a,b)class Complexdouble real,imag; public: ;Complex operator + (const
31、Complex &c1, const Complex &c2)Complex temp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; return temp;friend Complex operator + (const Complex &c1, const Complex &c2) 單目操作符重載函數(shù)的定義格式 operator #( ) 作為全局(友元)函數(shù)重載 單目操作符重載函數(shù)的使用格式 a;#a;或operator#(a);作為全局(友元)函數(shù)重載 為了能夠區(qū)分前置和后置+和的重載函數(shù),
32、它們的后置用法: operator+(,int);作為全局(友元)函數(shù)重載實例 重載操作符+,使其能夠?qū)崿F(xiàn)實數(shù)與復(fù)數(shù)的混合運算。class Complex double real,imag; public: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i; friend Complex operator + (const Complex &c1, const Complex &c2) friend Complex operator + (const Complex &c, double d
33、) friend Complex operator + (double d, const Complex &c)Complex a(1,2),b(3,4),c1,c2,c3;c1=a+b;c2=b+21.5c3=10.2+a;規(guī)則和限制 可以重載C+中除下列運算符外的所有運算符:. .* : ?: 只能重載C+語言中已有的運算符,不可臆造新的。 不改變原運算符的優(yōu)先級和結(jié)合性。 不能改變操作數(shù)個數(shù)。規(guī)則和限制(續(xù)) 經(jīng)重載的運算符,其操作數(shù)中至少應(yīng)該有一個是自定義類型。 在重載運算符()、-或者=時,運算符重載函數(shù)必須聲明為類的一個成員。對于其他的運算符,運算符重載函數(shù)可以是成員函數(shù)或
34、者友元函數(shù). 但在某些情況下,操作符必須以全局函數(shù)來重載,才能滿足使用上的要求。練習(xí) 如果在類對象a的類中重載運算符“+”,則a+3的顯示調(diào)用( )。 A. a.operator(3) ; B. a-operator+(3); C. a.operator+(3) ; D. 3.operator+(a) ;賦值運算符的重載 兩個同類對象之間可以賦值,其含義是用一兩個同類對象之間可以賦值,其含義是用一個對象的狀態(tài)來改變另一個對象的狀態(tài)。個對象的狀態(tài)來改變另一個對象的狀態(tài)。 C+編譯程序會為每個類定義一個隱式的賦編譯程序會為每個類定義一個隱式的賦值操作符重載函數(shù),其行為是逐個對成員進(jìn)行賦值操作符重載
35、函數(shù),其行為是逐個對成員進(jìn)行賦值操作。值操作。 對象的成員中有動態(tài)的數(shù)據(jù)類型時,就不能對象的成員中有動態(tài)的數(shù)據(jù)類型時,就不能直接相互賦值,否則在程序的編譯或執(zhí)行過程中直接相互賦值,否則在程序的編譯或執(zhí)行過程中出現(xiàn)編譯或運行錯誤。例如:出現(xiàn)編譯或運行錯誤。例如:class Cdemoclass Cdemo public:public:CDemo(char CDemo(char * *s)s) ps = new charstrlen(s) + 1;ps = new charstrlen(s) + 1;strcpy(ps, s);strcpy(ps, s); CDemo()CDemo() if (p
36、s)if (ps) delete ps;delete ps; void print()void print() coutpsendl;coutpsendl; private:private: char char * *ps;ps;void main()void main() CDemo d1(Key), d2(Mouse);CDemo d1(Key), d2(Mouse);d1 = d2;d1 = d2; class CDemoclass CDemopublic:public:CDemo&CDemo& operator = (const CDemo &a) operat
37、or = (const CDemo &a) if (a.ps) ps = a.ps; if (a.ps) ps = a.ps; else ps = 0; else ps = 0; return return * *this;this; private: private: char char * *ps;ps;賦值運算符的重載d1d2keyd1 = d2*ps*ps??臻g??臻g堆空間堆空間Mouse 除了會產(chǎn)生與默認(rèn)拷貝構(gòu)造函數(shù)可能產(chǎn)生的類似問題以外,還會導(dǎo)致內(nèi)存泄露。賦值運算符的重載class CDemoclass CDemopublic:public:CDemo&CDemo&
38、amp; operator = (const CDemo &a) operator = (const CDemo &a)if (ps) delete ps;if (ps) delete ps;if (a.ps)ps = new charstrlen(a.ps) + 1;if (a.ps)ps = new charstrlen(a.ps) + 1;strcpy(ps, a.ps);strcpy(ps, a.ps);else ps = 0;else ps = 0;return return * *this;this; private: private: char char * *p
39、s;ps;注意軟件工程知識:當(dāng)類的對象包含指向動態(tài)分配的內(nèi)存的指針時,如果不為其提供重載的賦值運算符重載函數(shù)和拷貝構(gòu)造函數(shù)會造成邏輯錯誤。軟件工程知識:通常要把構(gòu)造函數(shù)、析構(gòu)函數(shù)、重載的賦值運算符以及拷貝構(gòu)造函數(shù)一起提供給使用動態(tài)內(nèi)存分配的類。注意軟件工程知識:防止一個類對象賦值給另一個類對象是可以實現(xiàn)的,具體做法是將賦值操作聲明為該對象的private成員。注意 拷貝構(gòu)造函數(shù)和賦值操作符=重載函數(shù)區(qū)別: 創(chuàng)建一個對象時,用另一個已存在的同類對象對其初始化,調(diào)用拷貝構(gòu)造函數(shù)。 對兩個已存在的對象,通過賦值操作用其中一個對象來改變另一個對象的狀態(tài)時,調(diào)用賦值操作符=重載函數(shù)。 例如:A a; A
40、 b=a; b=a; 調(diào)用拷貝構(gòu)造函數(shù),調(diào)用拷貝構(gòu)造函數(shù),等價于等價于A b(a);調(diào)用賦值操作符重載函數(shù)調(diào)用賦值操作符重載函數(shù)賦值運算符不能重載為友元函數(shù),只能是賦值運算符不能重載為友元函數(shù),只能是一個非靜態(tài)成員函數(shù)。一個非靜態(tài)成員函數(shù)。 并且它不能被派生并且它不能被派生類繼承。類繼承。注意重載轉(zhuǎn)換運算符 在C+中,數(shù)據(jù)類型轉(zhuǎn)換對于基本數(shù)據(jù)類型有兩種方式: 1、隱式數(shù)據(jù)類轉(zhuǎn)換 2、顯式數(shù)據(jù)類型轉(zhuǎn)換,也叫強(qiáng)制類型轉(zhuǎn)換。 對于用戶自定義的類,C+也提供了定義類型轉(zhuǎn)換的機(jī)制,它通過帶一個參數(shù)的構(gòu)造函數(shù)和對類型轉(zhuǎn)換操作符重載來實現(xiàn)一個類與其他類型之間的轉(zhuǎn)換。 帶一個參數(shù)的構(gòu)造函數(shù)用作類型轉(zhuǎn)換 可用作
41、從一個基本數(shù)據(jù)類型或其他類到一個類的轉(zhuǎn)換。 參見工程 “轉(zhuǎn)換運算符”。帶一個參數(shù)的構(gòu)造函數(shù)用作類型轉(zhuǎn)換 自定義類型轉(zhuǎn)換 在一個類中,可以對類型轉(zhuǎn)換操作符進(jìn)行重載,從而實現(xiàn)從一個類到一個基本數(shù)據(jù)類型或一個其他類的轉(zhuǎn)換。 轉(zhuǎn)換運算符聲明形式 operator 類型名類型名 () ;自定義類型轉(zhuǎn)換class RMB public: RMB(double value=0.0) yuan =value; fen = (value-yuan)*100+0.5; void ShowRMB() coutyuan “元元” fen 分分 endl; operator double () return yuan+
42、fen/100.0; private:int yuan, fen;void main() RMB r1(1.01),r2(2.20); RMB r3; /顯式轉(zhuǎn)換類型顯式轉(zhuǎn)換類型 r3 = (double)r1+(double)r2; r3.ShowRMB(); /自動轉(zhuǎn)換類型自動轉(zhuǎn)換類型 r3=r1+2.40; r3.ShowRMB(); /自動轉(zhuǎn)換類型自動轉(zhuǎn)換類型 r3 =2.0-r1; r3.ShowRMB(); 對于對于r3=r1+2.40;的系統(tǒng)工作的系統(tǒng)工作1、尋找重載的成員函數(shù)、尋找重載的成員函數(shù)+運算符運算符2、尋找重載的友元函數(shù)、尋找重載的友元函數(shù)+運算符運算符3、尋找轉(zhuǎn)換運
43、算符、尋找轉(zhuǎn)換運算符4、驗證轉(zhuǎn)換后的類型是否支持、驗證轉(zhuǎn)換后的類型是否支持+運算。運算。 轉(zhuǎn)換運算符重載一般建議盡量少使用。轉(zhuǎn)換運算符重載一般建議盡量少使用。分析 歧義問題:同時有帶一個參數(shù)的構(gòu)造函數(shù)和類型轉(zhuǎn)換操作符重載函數(shù),有時會產(chǎn)生歧義。 參見工程“轉(zhuǎn)換運算符1” 解決: 顯示類型轉(zhuǎn)換 給帶一個參數(shù)的構(gòu)造函數(shù)加修飾符explicit,其含義是禁止把帶一個參數(shù)的構(gòu)造函數(shù)作為隱式類型轉(zhuǎn)換符來用。歧義問題string類 , namespace std 可以初始化:string s1( hi ); 重載了 (as in cout =, , =, b?a:b;float max(float a, f
44、loat b)return ab?a:b;char max(char a, char b)return ab?a:b;template T max(T a,T b)return ab?a:b;函數(shù)模板的定義和使用 函數(shù)模板的定義 關(guān)鍵字class可以用typename取代,效果完全相同 type1,type2:類型參數(shù),用來聲明函數(shù)模板參數(shù)類型,局部變量和返回值類型 函數(shù)模板的使用template 函數(shù)定義函數(shù)定義函數(shù)名函數(shù)名(參數(shù)列表參數(shù)列表)例 求絕對值函數(shù)的模板#includetemplateT abs(T x) return x0?-x:x; void main() int n=-5;
45、 double d=-5.5; coutabs(n)endl; coutabs(d)endl;運行結(jié)果:55.5 分析分析 編譯器從調(diào)用編譯器從調(diào)用abs()時實參的類型,推導(dǎo)出時實參的類型,推導(dǎo)出函數(shù)模板的類型參數(shù)。例如,對于調(diào)用表達(dá)函數(shù)模板的類型參數(shù)。例如,對于調(diào)用表達(dá)式式abs(n),由于實參,由于實參n為為int型,所以推導(dǎo)出型,所以推導(dǎo)出模板中類型參數(shù)模板中類型參數(shù)T為為int。 當(dāng)類型參數(shù)的含義確定后,編譯器將以函數(shù)當(dāng)類型參數(shù)的含義確定后,編譯器將以函數(shù)模板為樣板,生成一個函數(shù):模板為樣板,生成一個函數(shù):int abs(int x) return x0?-x:x; 例 求絕對值函數(shù)
46、的模板 實際上,函數(shù)模板定義了一系列重載的函數(shù),要使用函數(shù)模板所定義的函數(shù)(模板函數(shù)),首先必須對函數(shù)模板進(jìn)行實例化(生成具體的函數(shù))。函數(shù)模板的實例化函數(shù)模板的實例化通常是隱式的,即編譯程序會根據(jù)調(diào)用時通常是隱式的,即編譯程序會根據(jù)調(diào)用時實參的類型自動地把函數(shù)模板實例化為具實參的類型自動地把函數(shù)模板實例化為具體的函數(shù)體的函數(shù)。實例化函數(shù)模板-生成模板函數(shù) 有時編譯程序無法根據(jù)調(diào)用時的實參類型確定所調(diào)用的模板函數(shù),這時需要在程序中顯示地實例化函數(shù)模板。 如 abs(n);顯示實例化函數(shù)模板顯示實例化函數(shù)模板template T1 sum(T2 a,T3 b)int i;long lng;Sum
47、(i,lng);int i;long lng;Sum(i,lng);errorint i;long lng;Sum(i,lng);顯示實例化函數(shù)模板template T3 sum(T2 a,T1 b)int i;long lng;Sum(i,lng); errorint i;long lng;Sum(i,lng); OK 除了類型參數(shù),模板也可帶有非類型參數(shù)。如: template void f(T a) T tempsize; void main() f(1); 函數(shù)模板的非類型參數(shù)函數(shù)模板的非類型參數(shù) 非類型參數(shù)按常量對待 函數(shù)模板的形式參數(shù)表中除了使用參數(shù)化類型名以外,還可以使用確定類型
48、的參數(shù)。也就是說,函數(shù)模板的參數(shù)表中,一定要函數(shù)模板的參數(shù)表中,一定要包含參數(shù)化類型名,但不一定都使用參數(shù)包含參數(shù)化類型名,但不一定都使用參數(shù)化類型名?;愋兔_€可以根據(jù)需要,使用確定類型的參數(shù)。如整型的參數(shù)、實型的參數(shù),等等。 參見工程“模板”帶有確定類型的參數(shù)的函數(shù)模板 程序中使用了C+所定義的typeid運算符。它可以在程序運行時,顯示指定的數(shù)據(jù)的類型。使用的格式是: typeid(表達(dá)式).name() 或者typeid(類型標(biāo)識符).name() typeid運算符RTTI(運行時類型識別) 通過使用RTTI,程序可以在運行時通過基類的指針或者引用來得到所指對象的實際類型。主要有兩
49、個操作: typeid操作符:返回指針或者引用所指對象的實際類型。 dynamic_cast操作符:將基類類型的指針或引用安全地轉(zhuǎn)換為派生類型的指針或者引用。 注意:只有當(dāng)類中至少有一個虛函數(shù)時,才能返回我們所需的動態(tài)類型信息;否則,只能返回靜態(tài)類型信息。 例 求絕對值函數(shù)的模板#includetemplateT abs(T x) return x0?-x:x; void main() int n=-5; double d=-5.5; coutabs(n)endl; coutabs(d)”。如果要用對象來作實參,相應(yīng)的類中要對“”運算符進(jìn)行重載。 用戶定義的類取代類型參數(shù) #include t
50、emplateT max_value(T x,T y,T z)T max_value(T x,T y,T z)/函數(shù)模板的定義:求x、y、z的最大值 T temp;if(xy) temp = x;else temp = y;if(ztemp) temp =z;return temp; void main() Circle C1(2,3,5),C2(3,5,8),C3(3,2,6); coutmax_value(12,32,21)endl;/用整數(shù)作實參調(diào)用函數(shù)模板coutmax_value(a,A,9)endl; /用字符作實參調(diào)用函數(shù)模板coutmax_value(C1,C2,C3)endl
51、;coutmax_value(C1,C2,C3)(Circle m2)int operator(Circle m2)/重載“”運算符if(radiusm2.radius)return 1; else return 0; private: int x,y; / 圓心座標(biāo)double radius; / 圓半徑; ostream &operator( ostream &out, Circle &C1 ) outx=C1.x y=C1.y; out radius=C1.radius; return out; class Circle /Circle類的定義friend ost
52、ream &operator( ostream &, Circle & );friend ostream &operator(Circle m2)int operator(Circle m2)/重載“”運算符if(radiusm2.radius)return 1; else return 0; private: int x,y; / 圓心座標(biāo)double radius; / 圓半徑; void main() Circle C1(2,3,5),C2(3,5,8),C3(3,2,6); coutmax_value(12,32,21)endl;/用整數(shù)作實參調(diào)用函數(shù)模
53、板coutmax_value(a,A,9)endl; /用字符作實參調(diào)用函數(shù)模板coutmax_value(C1,C2,C3)endl; /用對象作參數(shù)調(diào)用函數(shù)模板程序運行結(jié)果是:程序運行結(jié)果是:3232a ax=3 y=5 radius=8 函數(shù)模板與函數(shù)重載 為了彌補函數(shù)模板所缺乏的一些靈活性,需要把函數(shù)模板與函數(shù)重載結(jié)合起來使用。template T max(T a,T b)return ab?a:b;int x,y,z;double l,m,n;z=max(x,y);l=max(m,n);max(x,m);max(x,m);max(x,m);double max(int a,doubl
54、e b)return ab?a:b;函數(shù)模板與函數(shù)重載 可以定義相同名字但形參數(shù)目或類型不同的多個函數(shù)模板,也可以定義和函數(shù)模板有相同名字的普通非模板函數(shù)函數(shù)模板與函數(shù)重載 函數(shù)模板和非模板函數(shù)重載的情況下,一個具體的函數(shù)調(diào)用,就有多個函數(shù)可供選擇。具體的選擇是根據(jù)函數(shù)調(diào)用所提供的參數(shù)進(jìn)行的。 首先尋找函數(shù)名和參數(shù)能精確匹配的非模板函數(shù) 如果沒有找到,選擇參數(shù)可以匹配的函數(shù)模板 如果還不成功,通過參數(shù)自動轉(zhuǎn)換,選擇非模板函數(shù)類模板 什么是類模板 類模板是用戶為類定義的一種模式,使類中的某些數(shù)據(jù)成員的類型、成員函數(shù)的參數(shù)或返回值能夠使用任意的數(shù)據(jù)類型類模板 類模版的定義 關(guān)鍵字class可以用t
55、ypename取代,效果完全相同 類型參數(shù)可以在成員函數(shù)和數(shù)據(jù)成員中作為數(shù)據(jù)類型使用template class ; 在類模板的外部定義類模板的成員函數(shù)時的格式: 首先要使用類模板的頭部,以表明類模板定義了幾個類型參數(shù); 作用域運算符“:”前面的類名用類模板名代替,而且也要在尖括號中注明所有類模板的類型參數(shù); 函數(shù)的參數(shù)表或者自動變量的定義,則是可以使用類型參數(shù),也可以不使用。類模板類模板 在類外部定義成員函數(shù)的格式如下: template 返回值類型返回值類型 類模板名類模板名 : 成員函數(shù)名成員函數(shù)名( 參數(shù)表參數(shù)表 ) 函數(shù)體函數(shù)體template /類模板:實現(xiàn)對任意類型數(shù)據(jù)進(jìn)行存取類
56、模板:實現(xiàn)對任意類型數(shù)據(jù)進(jìn)行存取class Store private: T item; / 用于存放任意類型的數(shù)據(jù)用于存放任意類型的數(shù)據(jù) int haveValue; / 用于標(biāo)記用于標(biāo)記item是否已被存是否已被存 入內(nèi)入內(nèi)容容 public: Store(); / 構(gòu)造函數(shù)構(gòu)造函數(shù) T GetElem(); /提取數(shù)據(jù)函數(shù)提取數(shù)據(jù)函數(shù) void PutElem(T x); /存入數(shù)據(jù)函數(shù)存入數(shù)據(jù)函數(shù);/ 缺省構(gòu)造函數(shù)的實現(xiàn)缺省構(gòu)造函數(shù)的實現(xiàn)template Store:Store(): haveValue(0) / 提取數(shù)據(jù)函數(shù)的實現(xiàn)提取數(shù)據(jù)函數(shù)的實現(xiàn)template T Store:G
57、etElem() / 如果試圖提取未初始化的數(shù)據(jù),則終止程序如果試圖提取未初始化的數(shù)據(jù),則終止程序 if (haveValue = 0) cout No item present! endl; exit(1); return item; / 返回返回item中存放的數(shù)據(jù)中存放的數(shù)據(jù) / 存入數(shù)據(jù)函數(shù)的實現(xiàn)存入數(shù)據(jù)函數(shù)的實現(xiàn) template void Store:PutElem(T x) haveValue+; / 將將haveValue 置為置為 TRUE,表示,表示item中已存入中已存入數(shù)值數(shù)值 item = x; / 將將x值存入值存入item類模板的實例化 函數(shù)模板在調(diào)用它或用它對函
58、數(shù)指針進(jìn)行初始化或賦值時實例化。類模板的實例化則是對象的實例化一起完成的,且需顯示實例化且需顯示實例化。 在類模板后面的尖括號中,表明取代類型參數(shù)的實際類型名; 再寫對象名和構(gòu)造對象所需要的實參數(shù)。 一般化的格式如下: 類模板名類模板名 對象名對象名(實參數(shù)實參數(shù));例 類模板應(yīng)用舉例#include #include / 結(jié)構(gòu)體Studentstruct Student int id; /學(xué)號 float gpa; /平均分; template /類模板:實現(xiàn)對任意類型數(shù)據(jù)進(jìn)行存取類模板:實現(xiàn)對任意類型數(shù)據(jù)進(jìn)行存取class Store private: T item; / 用于存放任意類型
59、的數(shù)據(jù)用于存放任意類型的數(shù)據(jù) int haveValue; / 用于標(biāo)記用于標(biāo)記item是否已被存是否已被存 入內(nèi)入內(nèi)容容 public: Store(); / 構(gòu)造函數(shù)構(gòu)造函數(shù) T GetElem(); /提取數(shù)據(jù)函數(shù)提取數(shù)據(jù)函數(shù) void PutElem(T x); /存入數(shù)據(jù)函數(shù)存入數(shù)據(jù)函數(shù);/ 缺省構(gòu)造函數(shù)的實現(xiàn)缺省構(gòu)造函數(shù)的實現(xiàn)template Store:Store(): haveValue(0) / 提取數(shù)據(jù)函數(shù)的實現(xiàn)提取數(shù)據(jù)函數(shù)的實現(xiàn)template T Store:GetElem() / 如果試圖提取未初始化的數(shù)據(jù),則終止程序如果試圖提取未初始化的數(shù)據(jù),則終止程序 if (h
60、aveValue = 0) cout No item present! endl; exit(1); return item; / 返回返回item中存放的數(shù)據(jù)中存放的數(shù)據(jù) / 存入數(shù)據(jù)函數(shù)的實現(xiàn)存入數(shù)據(jù)函數(shù)的實現(xiàn) template void Store:PutElem(T x) haveValue+; / 將將haveValue 置為置為 TRUE,表示,表示item中已存入中已存入數(shù)值數(shù)值 item = x; / 將將x值存入值存入itemvoid main(void) Student g= 1000, 23; Store S1, S2; Store S3; Store D; S1.PutElem(3); S2.PutElem(-7); cout S1.GetElem() S2.GetElem() endl; S3.PutElem(g); cout The student id is S3.GetElem().id endl;cout Retrieving object D ;cout D.GetElem() endl; /輸出對象D的數(shù)據(jù)成員/ 由于D未經(jīng)初始化,在執(zhí)行函數(shù)D.Get
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- JJF 2161-2024焊接檢驗尺校準(zhǔn)規(guī)范
- 2024年度年福建省高校教師資格證之高等教育心理學(xué)考前沖刺模擬試卷A卷含答案
- 2024年度年福建省高校教師資格證之高校教師職業(yè)道德綜合檢測試卷B卷含答案
- 2024年閘機(jī)系統(tǒng)投資申請報告
- 一年級數(shù)學(xué)計算題專項練習(xí)匯編
- 湖南省永州市高一上學(xué)期期末歷史試題及解答參考
- 2024商用中央空調(diào)全面檢修協(xié)議
- 2024年臨時租車服務(wù)協(xié)議詳案
- 2024年度代理服務(wù)協(xié)議樣本
- 2024年勞動協(xié)議格式大全
- 蘇教版五年級上冊數(shù)學(xué)試題-第一、二單元 測試卷【含答案】
- 發(fā)揮產(chǎn)業(yè)工會作用的實施方案
- 科捷物流介紹(中文版)ppt課件
- 軍事地形學(xué)地形圖基本知識
- 2022版義務(wù)教育(生物學(xué))課程標(biāo)準(zhǔn)(含2022年修訂和新增部分)
- 六年級綜合實踐活動課件-珍愛生命遠(yuǎn)離毒品 全國通用(共24張PPT)
- 建設(shè)工程竣工消防驗收記錄表(DOC36頁)
- 沉井專項施工方案DOC
- 切削力計算參考模板
- 一年級海洋教育教案
- 聚氨酯硬泡沫配方及計算
評論
0/150
提交評論