2.4多態(tài)與虛函數(shù)_第1頁
2.4多態(tài)與虛函數(shù)_第2頁
2.4多態(tài)與虛函數(shù)_第3頁
2.4多態(tài)與虛函數(shù)_第4頁
2.4多態(tài)與虛函數(shù)_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

面向?qū)ο蟪绦蛟O計4多態(tài)性與虛函數(shù)本章主要內(nèi)容多態(tài)性概述運算符重載虛函數(shù)抽象類多態(tài)性:發(fā)出同樣的消息被不同類型的對象接受導致完全不同的行為;多態(tài)可分為:靜態(tài)多態(tài)性與動態(tài)多態(tài)性;動態(tài)多態(tài)性必須存在于繼承的環(huán)境之中;多態(tài)性的概念4.1重載在類中,構造函數(shù)可以重載,普通成員函數(shù)也可以重載;構造函數(shù)重載給初始化帶來了多種方式,為用戶提供了更大的靈活性。一、函數(shù)重載二、運算符重載對已有運算符進行重新定義,使運算符的功能得以擴展二、運算符重載的幾個問題1、哪些運算符可以重載?算術運算符:+、-、*、/、%、++、--;位操作運算符:&、|、~、^、<<、>>;邏輯運算符:!、&&、||;比較運算符:>、<、>=、<=、==、!=;賦值運算符:=、+=、-=、*=、/=、%=、

&=、|=、~=、<<=、>>=;其他運算符:[]、()、->、'

、new、delete、

new[]、delete[]、->*;不允許重載的運算符:.、.、::、?:、sizeof;2、編譯程序如何選用哪一個運算符函數(shù)?運算符實質(zhì)上是函數(shù),遵循函數(shù)重載原則;3、運算符重載時必須遵循哪些原則?重載運算符含義必須清楚;重載運算符不能有二義性;4、重載運算符有哪些限制?不可臆造新的運算符;重載運算符堅持4個“不能改變”:不能改變運算符操作數(shù)的個數(shù);不能改變運算符原有的優(yōu)先級;不能改變運算符原有的結合性;不能改變運算符原有的語法結構;函數(shù)類型operator運算符名稱(形參表列){對運算符的重載處理}其參數(shù)中至少有一個為類對象或類對象的引用。重載運算符的使用方法:

與原運算符相同三、運算符重載函數(shù)一般格式四、運算符重載函數(shù)的兩種形式1、重載為類的成員函數(shù)重載一元運算符,不再顯式說明參數(shù);重載二元運算符,只顯式說明一個參數(shù);該參數(shù)為操作數(shù)的右操作數(shù),左操作數(shù)由this指針(指向調(diào)用該成員函數(shù)的對象)提供;重載為成員函數(shù)時,隱含了一個參數(shù)(this指針);例:分析下列程序#include<iostream.h>classcomplex{public:

complex(doubler=0,doublei=0);

complexoperator+(constcomplex&c);//+運算符

complexoperator-(constcomplex&c);//-運算符

complexoperator-();//取負運算符voidprint()const;private:doublereal,imag;};complex::complex(doubler,doublei){real=r;imag=i;}complexcomplex::operator+(constcomplex&c){doubler=real+c.real;doublei=imag+c.imag;returncomplex(r,i);}complexcomplex::operator-(constcomplex&c){doubler=real-c.real;doublei=imag-c.imag;returncomplex(r,i);}complexcomplex::operator-(){returncomplex(-real,-imag);}voidcomplex::print()const{cout<<'('<<real<<','<<imag<<')'<<endl;}voidmain(){complexc1(2.5,3.7),c2(4.2,6.5);complexc;c=c1-c2;c.print();c=c1+c2;

c.print();c=-c1;

c.print();}c=c1.operator-(c2);c=c1.operator+(c2);輸出(-1.7,-2.8)

(6.7,10.2)

(-2.5,-3.7)c=c1.operator-();2、重載為友元函數(shù)重載為友元函數(shù)時,沒有隱含的參數(shù)this指針,即不改變原有運算符的語法結構;下列運算符不能重載為友元函數(shù):

=、()、[]、->重載為友元函數(shù)的運算符重載函數(shù)的格式:friend<類型說明符>operator<運算符>(<參數(shù)表>){……}例:分析下列程序的輸出結果。#include<iostream.h>classcomplex{public:

complex(doubler=0,doublei=0);friendcomplexoperator+//+運算符(constcomplex&c1,constcomplex&c2);

friendcomplex

operator-//

-運算符(constcomplex&c1,constcomplex&c2);

friendcomplexoperator-(constcomplex&c);//求負運算符voidprint()const;private:doublereal,imag;};complex::complex(double

r,doublei){real=r;imag=i;}complexoperator+(constcomplex&c1,constcomplex&c2){doubler=c1.real+c2.real;doublei=c1.imag+c2.imag;returncomplex(r,i);}complexoperator-(constcomplex&c1,constcomplex&c2){doubler=c1.real-c2.real;doublei=c1.imag-c2.imag;returncomplex(r,i);}complexoperator-(constcomplex&c){returncomplex(-c.real,-c.imag);}voidcomplex::print()const{cout<<'('<<real<<','<<imag<<')'<<endl;}voidmain(){complexc1(2.5,3.7),c2(4.2,6.5);complexc;c=c1-c2;

c.print();c=c1+c2;

c.print();c=-c1;

c.print();}c=operator-(c1,c2);c=operator+(c1,c2);c=operator-(c1);輸出(-1.7,-2.8)

(6.7,10.2)

(-2.5,-3.7)3、兩種重載形式的比較一般情況下,單目運算符最好重載為成員函數(shù);雙目運算符則最好重載為友元函數(shù);有些雙目運算符重載為成員函數(shù)較好:

如:賦值運算符=;概念:靜態(tài)關聯(lián):在編譯時進行的關聯(lián),即編譯時就確定了程序中的操作調(diào)用與執(zhí)行該操作代碼之間的關系。關聯(lián):確定調(diào)用具體對象的過程。(把一個標識符和一個地址聯(lián)系起來)4.2靜態(tài)關聯(lián)和動態(tài)關聯(lián)動態(tài)關聯(lián):在程序執(zhí)行時進行的關聯(lián);實現(xiàn):C++動態(tài)關聯(lián)在虛函數(shù)的支持下實現(xiàn);4.3虛函數(shù)1、虛函數(shù)虛函數(shù)是動態(tài)關聯(lián)的基礎;虛函數(shù)是非static成員函數(shù);virtual<類型說明符><函數(shù)名>(<參數(shù)表>)說明方法:含義:若類中一成員函數(shù)被說明為虛函數(shù),則該成員函數(shù)在派生類中可能有不同的實現(xiàn)。當使用該成員函數(shù)操作指針或引用所標識的對象時,對該成員函數(shù)調(diào)用可采用動態(tài)關聯(lián)方式。例:分析下列程序的輸出結果。#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}

virtualdoubleArea()const{return0;}//虛函數(shù)private:doublex,y;};classRectangle:publicPoint{public:

Rectangle(int

i,int

j,int

k,intl);

virtualdoubleArea()const{returnw*h;}//虛函數(shù)private:doublew,h;};Rectangle::Rectangle(int

i,int

j,int

k,intl):Point(i,j){w=k;h=l;}voidfun(Point&s){cout<<s.Area()<<endl;}voidmain(){

Rectanglerect(3.0,5.2,15.0,25.0);

fun(rect);}輸出:

375例:分析下列程序,回答問題。#include<iostream.h>classA{public:

virtual

voidact1(){cout<<"A::act1()called."<<endl;}//虛函數(shù)voidact2(){act1();}};classB:publicA//公有繼承{public:

voidact1(){cout<<"B::act1()called."<<endl;}};voidmain(){Bb;b.act2();}回答下列問題:(1)、該程序執(zhí)行后的輸出結果是什么?為什么?輸出結果為:B::act1()called.原因:a.B從A公有繼承,B是A的子類型,A的成員成為B的成員

b.A中的act1()為虛函數(shù);b.act2()調(diào)用B的是成員函數(shù)

c.b.act2(),進一步調(diào)用act1(),產(chǎn)生動態(tài)關聯(lián),運行時選擇B::act1();(2)、如果將A::act2()的實現(xiàn)改為:

voidA::act2(){this->act1();}

輸出結果是什么?為什么?輸出結果與(1)相同,即:B::act1()called.原因:this指向操作該成員函數(shù)的對象,基于與(1)相同的原因,此處調(diào)用B::act1()。(3)、如果將A::act2()的實現(xiàn)改為:

voidA::act2()

{A::act1();

}

輸出結果是什么?為什么?輸出結果:A::act1()called.原因:此處增加了成員名限定,因此要進行靜態(tài)關聯(lián),即調(diào)用的是A::act1()。派生類中對基類的虛函數(shù)進行替換時,要求派生類中說明的虛函數(shù)與基類中的被替換的虛函數(shù)之間滿足下列條件:參數(shù)個數(shù):與基類的虛函數(shù)有相同的參數(shù)個數(shù);參數(shù)類型:與基類的虛函數(shù)的對應參數(shù)類型相同;返回值類型:與基類的虛函數(shù)的返回值類型相同;都返回指針或引用,并且派生類虛函數(shù)所返回的指針或引用的基類型是基類中被替換的虛函數(shù)所返回的指針或引用的基類型的子類型;基類中定義了虛成員函數(shù)后,派生類的同名函數(shù)都自動成為虛函數(shù),可不加virtual說明。構造函數(shù)與析構函數(shù)調(diào)用虛函數(shù)構造函數(shù)中調(diào)用虛函數(shù)時,采用靜態(tài)關聯(lián),即構造函數(shù)調(diào)用的虛函數(shù)是自己類中實現(xiàn)的虛函數(shù),如果自己類中沒有實現(xiàn)這個虛函數(shù),則調(diào)用基類中的虛函數(shù),而不是任何派生類中實現(xiàn)的虛函數(shù);析構函數(shù)中調(diào)用虛函數(shù)同構造函數(shù),即析構函數(shù)所調(diào)用的虛函數(shù)是自身類中的或者基類中實現(xiàn)的虛函數(shù);BAC構造(析構)函數(shù)一般成員函數(shù)調(diào)用虛函數(shù)

純虛函數(shù)1、引入在基類中不能為虛函數(shù)給出一個有意義的實現(xiàn)時,可將其聲明為純虛函數(shù),其實現(xiàn)留待派生類完成;2、作用為派生類提供一個一致的接口;3、聲明格式

class<類名>

{

virtual

<類型><函數(shù)名>(<參數(shù)表>)

=

0;

……

}例:分析下列程序的輸出結果。#include<iostream.h>classPoint{public:

Point(inti=0,intj=0){x0=i;y0=j;}

virtual

voidSet()=0;virtualvoidDraw()=0;protected:intx0,y0;};classLine:publicPoint{public:

Line(inti=0,intj=0,intm=0,intn=0):Point(i,j){x1=m;y1=n;}voidSet(){cout<<"Line::Set()called."<<endl;}voidDraw(){cout<<"Line::Draw()called."<<endl;}protected:intx1,y1;};classEllipse:publicPoint{public:

Ellipse(inti=0,intj=0,intp=0,intq=0):Point(i,j){x2=p;y2=q;}voidSet(){cout<<"Ellipse::Set()called."<<endl;}voidDraw(){cout<<"Ellipse::Draw()called."<<endl;}protected:intx2,y2;};voidDrawObj(Point*p){p->Draw();}voidSetObj(Point*p){p->Set();}voidmain(){Line*lineobj=newLine;Ellipse*ellipseobj=newEllipse;

DrawObj(lineobj);

DrawObj(ellipseobj);

SetObj(lineobj);

SetObj(ellipseobj);

cout<<"Redrawtheobject…"<<endl;

DrawObj(lineobj);

DrawObj(ellipseobj);}執(zhí)行結果Line::Draw()called.Ellipse::Draw()called.Line::Set()called.Ellipse::Set()called.Redrawtheobject...Line::Draw()called.Ellipse::Draw()called.4.4抽象類帶有純虛函數(shù)的類稱為抽象類;抽象類只能作為基類使用,其純虛函數(shù)的實現(xiàn)由派生類給出;但派生類仍可不給出純虛函數(shù)的定義,繼續(xù)作為抽象類存在;抽象類不能定義對象,一般將該類的構造函數(shù)說明為保護的訪問控制權限;抽象類的作用:用作基類:在繼承層次結構中,提供一個公共的根,基于抽象類的操作設計出對抽象類所描述的一類對象進行操作的公共接口,其完整的實現(xiàn)由派生類完成;用作指針或引用的基類型:保證進入繼承層次的每個類都具有(提供)純虛函數(shù)所要求的行為;在成員函數(shù)內(nèi)可以調(diào)用純虛函數(shù),但在構造函數(shù)或析構函數(shù)內(nèi)不能調(diào)用純虛函數(shù)(純虛函數(shù)沒有實現(xiàn)代碼);

classA

{

public:

virtual

voidf()=0;

voidg(){f();}//正確

A(){f();}//錯誤

}4.5虛析構函數(shù)虛析構函數(shù)

在析構函數(shù)前加關鍵字virtual進行說明,則該析構函數(shù)稱為虛析構函數(shù);格式:

classB

{

public:

virtual

~B();

…...

}如果一個類的析構函數(shù)被說明

溫馨提示

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

最新文檔

評論

0/150

提交評論