c++面向?qū)ο蟪绦蛟O計第3章-類和對象課件_第1頁
c++面向?qū)ο蟪绦蛟O計第3章-類和對象課件_第2頁
c++面向?qū)ο蟪绦蛟O計第3章-類和對象課件_第3頁
c++面向?qū)ο蟪绦蛟O計第3章-類和對象課件_第4頁
c++面向?qū)ο蟪绦蛟O計第3章-類和對象課件_第5頁
已閱讀5頁,還剩163頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第3章類和對象本章介紹類與對象的定義、成員函數(shù)、構造函數(shù)、析構函數(shù)、對象與指針等基本概念及應用,講解C++的繼承、重載、多太性等特性,使讀者掌握C++的編程基本知識。第3章類和對象本章介紹類與對象的定義、成員13.1類與對象的定義3.2成員函數(shù)3.3構造函數(shù)3.4析構函數(shù)3.5對象與指針3.6類與結構3.7繼承3.8多重繼承3.9派生類的對象和構造函數(shù)3.10多態(tài)性3.11重載3.12虛擬函數(shù)實驗3類和對象、繼承和派生3.1類與對象的定義21.類的定義類定義的語法如下:class類名{private:數(shù)據(jù)成員或成員函數(shù);public:數(shù)據(jù)成員或成員函數(shù);protected:數(shù)據(jù)成員或成員函數(shù);};

3.1類與對象的定義類的定義由兩大部分組成,即類的數(shù)據(jù)成員和成員函數(shù)。類的數(shù)據(jù)成員和成員函數(shù)也稱為類的屬性和類的操作。數(shù)據(jù)成員類似C結構中的變量,成員函數(shù)定義了類對數(shù)據(jù)的操作,反映了類行為和類的能力。1.類的定義3.1類與對象的定義類的定義由兩大部3例3.1:定義一個student類,用以描述學生對象。

123例3.1:定義一個student類,用以描述學生對象。4

classStudent{private:charm_Name[20];intm_Age;intm_Sex;charm_cl[20];intm_number;public:voidRegister(char*Name,intAge,charSex,char*cl,intnumber);voidGetName(char*Name);intGetAge();charGetSex();voidGetcl(char*cl);intGetnumber();};程序?qū)崿F(xiàn):

52.對象的定義對象是類的實例。從技術上講,一個對象就是一個具有某種類類型的變量。與普通變量一樣,對象也必須先經(jīng)聲明才可以使用。

聲明一個對象的一般形式為:<類名><對象1>,<對象2>,…例:StudentStudent1,Student2;聲明了兩個名為Student1和Student2的Student類的對象。2.對象的定義對象是類的實例。從技術上講,一6

在程序中使用一個對象,通常是通過對體現(xiàn)對象特征的數(shù)據(jù)成員的操作實現(xiàn)的。當然,由于封裝性的要求,這些操作又是通過對象的成員函數(shù)實現(xiàn)的。具體來說:(1)成員函數(shù)訪問同類中的數(shù)據(jù)成員,或調(diào)用同類中的其他成員函數(shù),可直接使用數(shù)據(jù)成員名或成員函數(shù)名;(2)在對象外訪問其數(shù)據(jù)成員或成員函數(shù)需使用運算符“.”訪問對象的成員,例如:number=Student1.Getnumber();(3)不能直接訪問一個對象中的私有成員,如果直接訪問則導致語法錯誤;(4)同類對象之間可以整體賦值。例如:Student2=Student1;(5)對象用作函數(shù)的參數(shù)時屬于賦值調(diào)用;函數(shù)可以返回一個對象。在程序中使用一個73.2成員函數(shù)在類的定義中僅給出了成員函數(shù)的原型,函數(shù)的定義還需在其他地方(通常每個類的成員函數(shù)的定義放在一起構成一個源程序文件)給出。類的成員函數(shù)的一般形式為:<類型><類名>::函數(shù)名(<參數(shù)表>){?函數(shù)體?}其中作用域運算符“::”指出成員函數(shù)的類屬。沒有類屬的函數(shù)稱為公共函數(shù)。

3.2成員函數(shù)在類的定義中僅給出了成員函8例3.2.1類成員函數(shù)的定義。說明:按例3-1說明的方法添加頭文件Student.h,輸入Student類的定義。然后為項目添加一源代碼文件Student.cpp//Example(Student.cpp):Student類成員函數(shù)的定義#include<string.h>#include“Student.h”voidStudent::Register(char*Name,intAge,charSex,char*class,intnumber);{strcpy(m_Name,name);m_Age=age;m_Sex=(sex==’m’?0:1);strcpy((m_cl,cl);m_number=number;}

例3.2.1類成員函數(shù)的定義。說明:按例3-1說明的方9voidStudent::GetName(char*name){strcpy(name,m_Name);}intStudent::GetAge(){returnm_Age;}charStudent::GetSex(){return(m_Sex==0?‘m’:‘f’):}voidStudent::Getcl(char*cl){strcpy(cl,m_cl);}intStudent::Getnumber(){returnm_number}voidStudent::GetName(char*10例3.2.2定義Student類,并將類Student的成員函數(shù)聲明為內(nèi)聯(lián)函數(shù)

。clStudent{private:charm_Name[20];intm_Age;intm_Sex;charm_cl[20];intm_number;public:voidRegister(char*Name,intAge,charSex,char*cl,intnumber){strcpy(m_Name,name);m_Age=age;m_Sex=(sex==’m’?0:1);strcpy((m_cl,cl);m_number=number;}例3.2.2定義Student類,并將類Student的成11voidGetName(char*Name){strcpy(name,m_Name);}intGetAge(){returnm_Age;}charGetSex(){return(m_Sex==0?‘m’:‘f’);}voidGetcl(char*cl){strcpy(cl,m_cl);}intGetnumber(){returnm_number}};voidGetName(char*Name)12例3.2.3學生資料的輸入輸出。//Example:學生資料的輸入和輸出#include<iostream.h>#voidmain(){voidOutStudentData(Student);charname[20],sex;intage;charcl[20];intnumber;StudentStudent1,Studen2;cout<<“EnteraStudent’sname、age、sex、cland.number:”;cin>>name>>age>>sex>>cl>>number;Student1.Register(name,age,sex,cl,number);Student2.Register(“Zhang2”,19,’m’,“9901”,100);cout<<“student1:\t”;OutStudentData(Student1);cout<<“Student2:\t”;OutStudentData(Student2);Student2=Student1;Cout<<“Student3:\t”;OutStudentData(Student2);}例3.2.3學生資料的輸入輸出。//Example:學13voidOutStudentData(Student);{charname[20];charcl[20];Student.GetName(name);Student.GetCl(cl)cout<<name<<“\t”<<Student.GetAge()<<“\t”<<Student.GetSex()<<“\t”<<cl<<“\t”<<Student.Getnumber()<<end1;}EnteraStudent’sname、age、sex、clandnumber:zhang120’f’“9901”101輸入:Student1:zhang120f9901101輸出EnteraStudent’sname、age、sex、clandnumber:zhang219’m’“9902”100輸入:Student2:zhang219m9902100輸出EnteraStudent’sname、age、sex、clandnumber:zhang320’f’“9901”102輸入:Student3:zhang320f9901102輸出voidOutStudentData(Student);E143.3構造函數(shù)構造函數(shù)是與類名相同的特殊成員函數(shù),當定義對象或者用new動態(tài)生成對象時,編譯程序?qū)⒆詣诱{(diào)用構造函數(shù)以實現(xiàn)對象的初始化。構造函數(shù)與普通成員函數(shù)的區(qū)別,是不允許指定返回類型,也不返回值。構造函數(shù)允許重載。構造函數(shù)的聲明格式為:<類名>(<參數(shù)表>);3.3構造函數(shù)構造函數(shù)是與類名相同的特殊成15例3.3.1為類Student增加構造函數(shù)。//Example:為類Student增加構造函數(shù)#include<string.h>classStudent{Private:charm_Name[20];intm_Age;intm_Sex;charm_cl[20];intm_number;Public:Student(constchar*name,intage,charsex,constcharcl,intnumber)

例3.3.1為類Student增加構造函數(shù)。//Exa16//構造函數(shù){strcpy(m_Name,name);m_Age=age;m_Sex=(sex=’m’?0:1);strcpy(m_cl,cl);m_number=number;}voidRegister(char*Name,intAge,charSex,char*cl,intnumber);voidGetName(char*Name);intGetAge();charGetSex();voidGetcl(char*cl);intGetnumber();};說明:如果在類中沒有聲明任何構造函數(shù)的話,系統(tǒng)會自動地為它定義一個形如<類名>::<類名>()的缺省構造函數(shù),這種不帶任何參數(shù)且函數(shù)體為空的構造函數(shù)就叫做缺省的構造函數(shù)。如果在類聲明中已經(jīng)定義了構造函數(shù),則系統(tǒng)不再提供缺省的構造函數(shù)。//構造函數(shù)說明:如果在類中沒有聲明任何構造函數(shù)的話,系統(tǒng)會173.4析構函數(shù)析構函數(shù)的函數(shù)名是在類名前加波浪名“~”的特殊成員函數(shù)。析構函數(shù)與構造函數(shù)的功能正好相反;構造函數(shù)在對象生成時為其他分配存儲空間,而析構函數(shù)的功能是在對象銷毀時釋放它所占用的內(nèi)存。析構函數(shù)與構造函數(shù)一樣沒有返回值,但它不帶參數(shù),不能被重載。

析構函數(shù)的聲明方法為:classExample{public:~Example();//析構函數(shù);};

當類的聲明中沒有定義析構函數(shù)時,C++編譯程序會自動產(chǎn)生一個默認的析構函數(shù)。。

3.4析構函數(shù)析構函數(shù)的函數(shù)名是在類名前18例:#include<iostream.h>classExample{public:Example();~Example();};Example(){cout<<“Objectiscreated!”<<\\n;}Example::~Example(){cout<<“Objectisdestroyed!”<<endl;}voidmain(){ExampleEx;}Objectiscreated!Objectisdestroyed!執(zhí)行結果例:#include<iostream.h>Object193.5對象與指針可以聲明指向?qū)ο蟮闹羔?,方法與聲明指向變量的指針相同。例如:

StudentStudent1(“Zhang”,19,’f’);Student*ptr=&Student1;通過指針訪問對象的成員要用運算符“->”,例如:

Ptr->GetAge();當對象接收到一個消息時,便會調(diào)用相應的成員函數(shù)。這時,系統(tǒng)會向該成員函數(shù)傳遞一個隱含的參數(shù),即指向該對象自身的指針,即this指針。一般來說,this指針用途不大,因為在成員函數(shù)中可以直接使用本對象內(nèi)部的所有成員變量和成員函數(shù)。但在某些場合中調(diào)用其他類的成員函數(shù)時,可能需用要傳送本對象的地址,在Windows程序設計中這種情況很多,這時就要用到this指針。

3.5對象與指針可以聲明指向?qū)ο蟮闹羔槪?03.6類與結構C++中有一個結構體類型,其定義和使用方法與類非常相似。

結構體類型的定義方法如下:Struct<結構體類型名>{<結構體類型的成員變量聲明語句表>};3.6類與結構C++中有一個結構體類型,21例:可定義一個表示日期的結構體類型。structdate{intda_year;intda_mon;intda_day;};即一個日期類型的變量有3個成員變量:年份(da_year)、月份(da_mon)和日(da_day)。例:可定義一個表示日期的結構體類型。structdate22在定義好結構體類型以后,就可以定義該類型的變量了:

struct<結構體類型名><變量表>;注意在定義時可以略去結構體類型說明符struct,這一點與C語言不同。例:變量聲明語句。dateyesterday,today,tomorrow;聲明了3個日期類型的變量:yesterday、today和tomorrow。

結構體類型的變量可用作函數(shù)的參數(shù)或者函數(shù)的返回值。

對結構體類型變量的成員變量的引用方法與類相同:<結構體類型變量名>.<成員變量名>例:today.da_year=2001;today.da_mon=10;today.da_day=10;在定義好結構體類型以后,就可以定義該類型的變量了233.7繼承繼承性是面向?qū)ο蟪绦蛟O計語言的主要特征之一。繼承性指的是一個新類可以從現(xiàn)有的類中派生出來,繼承該類的特性。被繼承的類稱為基類(baseclass)或父類(parentclass),繼承的類稱為派生類(derivedclass)或子類(childclass)。繼承性允許建立類層次結構,是程序中代碼可復用性的關鍵,并提供對多態(tài)性的支持,是C++面向?qū)ο蟪绦蛟O計的基石。3.7繼承繼承性是面向?qū)ο蟪绦蛟O計語言的主243.7繼承1.繼承與類層次結構生物動物植物微生物爬行動物哺乳動物鳥類貓科動物貓圖人類認識事物的抽象層次3.7繼承1.繼承與類層次結構生物動物植物微生物爬行動25在軟件設計中,人們模擬這一過程。在面向?qū)ο蟮某绦蛟O計中,繼承提供了重用已有代碼生成新類的方法。繼承在類之間建立了關系。子類可以繼承父類的所有數(shù)據(jù)結構和操作,只要在子類中添加父類沒有的數(shù)據(jù)結構和操作。在上圖中,對象類型CButton是從CWnd派生出來的,CWnd是從CCmdTarget派生出來的,而CCmdTarget又是從CObject派生出來的。CObjectCCmdTargetCByteArrayCCmdTargetCframeWndCDialogCButton在軟件設計中,人們模擬這一過程。在面向?qū)ο蟮某绦蛟O計中262.派生類的工作方式

在C++程序中,當一個類是從一個基類派生出來的時候,該派生類就繼承了基類所有的成員變量和成員函數(shù),而且可以加入自己的成員變量和成員函數(shù)。但是,基類中聲明為私有的成員變量和成員函數(shù)是不可為派生類訪問的。

基類變量1變量2函數(shù)1函數(shù)2派生類其他變量其他函數(shù)圖說明基類和派生類之間的層次關系2.派生類的工作方式基類派生類圖說明基類和派生類之27

3.派生一個類聲明一個派生類的語法形式為:

class派生類名稱:繼承權限基類名稱{┇};其中,繼承權限說明符有三種:public、private和protected,默認權限為private。在類的定義中,所有公有成員都允許其他函數(shù)訪問,而私有成員則只能供成員函數(shù)訪問。但是,當派生類繼承基類的特性時,派生類無法訪問基類中的私有成員。若想讓基類中的某些成員不僅可供成員函數(shù)訪問,而且可將其特性傳給派生類,那么應將其聲明為保護類型。

28

例:類繼承的例子

。#include<iostream.h>classparent //聲明基類{inti;//私有成員變量i僅供成員函數(shù)使用,不能傳遞給派生類protected: //受保護成員變量僅供成員函數(shù)使用,可供派生類使用 intx;public: //公有成員,可供任何函數(shù)使用parent();voidchange();voidshow();};parent::parent() //定義構造函數(shù){ x=0; i=0;}voidparent::change() //定義成員函數(shù){ x++; i++;}

29voidparent::show() //定義成員函數(shù){ cout<<”x=”<<x<<”\n”;}classson:publicparent//聲明son為parent的派生類,繼承權限為public,即parent類的//公有成員在son中仍為公有成員,parent類的保護成員在son中仍為//保護成員{public: voidincrease(); //聲明成員函數(shù)};voidson::increase() //定義成員函數(shù)體{ x++;}保護成員變量x公有成員函數(shù)parent公有成員函數(shù)change公有成員函數(shù)increase公有成員函數(shù)show

經(jīng)過類繼承,派生類son訪問以下成員voidparent::show() //定義成員函數(shù)30

例某公司使用EMPINFO程序管理自己的雇員信息。后來,當該公司在國外開了分支機構而且雇傭不止一個國家的雇員時,如何重新設計EMPINFO程序呢?提示:為了滿足跨國公司的需要,程序設計者從EMPINFO程序中使用的EmpInfo類派生了一個新類,名為OffshoreEmpInfo。#include<iostream.h>classEmpInfo //基類{public:EmpInfo(){} //構造函數(shù)和析構函數(shù)~EmpInfo(){}private: char*m_name; char*m_dept;char*m_position;longm_salary;例某公司使用EMPINFO程序管理自31public: voidSetName(char*name){m_name=name;}//設置員變量的值 voidSetDept(char*dept){m_dept=dept;} voidSetPosition(char*position) {m_position=position;} SetSalary(longsalary) {m_salary=salary;} voidPrintInfo();};classOffshoreEmpInfo:publicEmpInfo //派生類{public: OffshoreEmpInfo(){} //構造函數(shù)和析構函數(shù) ~OffshoreEmpInfo(){} private: char*m_country;public: voidSetCountry(char*country) {m_country=country;}voidPintInfo();};public:32voidEmpInfo::PrintInfo(){ cout<<”Name:”<<m_name<<”\n”; cout<<”Department:”<<m_dept<<”\n”; cout<<”Position:”<<m_position<<”\n”; cout<<”Salary:”<<m_salary<<”\n”;}voidOffshoreEmpInfo::PrintInfo(){ EmpInfo::PrintInfo(); Cout<<“Country:”<<m_Country<<“\n”;}intmain(){OffshoreEmpInfoempInfo; //定義類OffshoreEmpInfo的對象empInfo.SetName(“PaulNorton”);empInfo.SetDept(“Development”);empInfo.SetPosition(“Engineer”);empInfo.SetSalary(24000);empInfo.SetCountry(“NewZealand”);empInfo.PrintInfo();return0;}Name:PaulNortonDepartment:DevelopmentPosition:EngineerSalary:24000Country:NewZealand輸出voidEmpInfo::PrintInfo()Name:333.8多重繼承基類與派生類之間可以有復雜的多對多關系。在類繼承中,允許某個類同時繼承多個基類,即所謂類的多重繼承。在類的多重繼承中,基類和派生類間是多對一的關系?;?基類2基類n……派生類繼承

繼承

繼承

繼承

3.8多重繼承基類與派生類之間可以有復雜的多對34

通過多重繼承,派生類將繼承多個基類的特性,此時基類和派生類的聲明方式為:

classN1 //聲明基類N1{┇};┇classNm //聲明基類Nm{┇};classS:publicN1,…,publicNm //聲明派生類S同時繼承基類N1,…,基類Nm{┇};注意:繼承一個以上的基類,要使用逗號分隔的表,還要確保為每個被繼承的基類使用一個繼承權限說明符。通過多重繼承,派生類將繼承多個基類的特性,此35例:兩用沙發(fā)是一個沙發(fā),也是一張床,兩用沙發(fā)同時具有沙發(fā)和床的特性。程序中類SleeperSofa繼承Bed和Sofa兩個類。#include<iostream.h>classSofa{protected: intlength;public: Sofa():length(0){} voidSitOn() {cout<<"Sitting...\n";}voidSetLength(inti){length=i;}};classBed{protected: intlength;public: Bed():length(0){} voidSleep(){cout<<"Sleeping...\n";}voidSetLength(inti){length=i;}};例:兩用沙發(fā)是一個沙發(fā),也是一張床,兩用沙發(fā)同時具有沙發(fā)和床36classSleepSofa:publicSofa,publicBed //繼承多個基類{public:SleepSofa(){} voidFoldOut() //折疊與打開{cout<<”Folt/Outthesofa.\n”;}};voidmain(){SleepSofasf;sf.SitOn();sf.FoldOut();sf.Sleep();}Sitting...Folt/Outthesofa.Sleeping...運行結果classSleepSofa:publicSofa,p373.9派生類的對象和構造函數(shù)1.派生類的對象用某個基類聲明一個派生類后,仍然可以利用基類來聲明對象,而且所聲明的對象和派生類所聲明的對象不會沖突。voidmain(){sonob1; //用派生類son定義一個對象ob1parentob2; //用基類parent定義一個對象ob2cout<<”Displayderivedclassobjectob1”;ob1.show(); //對象ob1的顯示結果ob1.change(); //調(diào)用從基類中繼承的成員函數(shù)ob1.increase(); //調(diào)用派生類中聲明的成員函數(shù)cout<<”Displaybaseclassobjectob2”;ob2.change();ob2.show();}Displayderivedclassobjectob1x=0Displaybaseclassobjectob2x=1運行結果3.9派生類的對象和構造函數(shù)1.派生類的對象void381.派生類的對象用某個基類聲明一個派生類后,仍然可以利用基類來聲明對象,而且所聲明的對象和派生類所聲明的對象不會沖突。voidmain(){sonob1; //用派生類son定義一個對象ob1parentob2; //用基類parent定義一個對象ob2cout<<”Displayderivedclassobjectob1”;ob1.show(); //對象ob1的顯示結果ob1.change(); //調(diào)用從基類中繼承的成員函數(shù)ob1.increase(); //調(diào)用派生類中聲明的成員函數(shù)cout<<”Displaybaseclassobjectob2”;ob2.change();ob2.show();}Displayderivedclassobjectob1x=0Displaybaseclassobjectob2x=1運行結果1.派生類的對象voidmain()Displayder392.派生類對象的構造函數(shù)和析構函數(shù)#include<iostream.h>classbase{public:base(){cout<<”Constructingbase\n”;}~base(){cout<<”Destructingbase\n”;}};classderived:publicbase{public:derived(){cout<<”{cout<<”Constructingderived\n”;}~base(){cout<<”Destructingderived\n”;}};main(){derivedob;//donothingbutconstructanddestructobreturn0;}ConstructingbaseconstructingderivedDestructingderivedDestructingbase運行結果2.派生類對象的構造函數(shù)和析構函數(shù)Constructing40由此可得出一般性的結論:當創(chuàng)建派生類的對象時,如果基類包含構造函數(shù),它將首先執(zhí)行,派生類的構造函數(shù)緊隨其后。當撤消派生類的對象時,它的析構函數(shù)將首先執(zhí)行,如果基類包含析構函數(shù),其析構函數(shù)將緊隨其后。換句話說,構造函數(shù)按其引入的順序執(zhí)行,析構函數(shù)按其引入的相反順序執(zhí)行。在多層繼承的情況下(即一個派生類成為另一個派生類的基類),一般規(guī)則是,構造函數(shù)按引入的順序執(zhí)行,析構函數(shù)按反序執(zhí)行。由此可得出一般性的結論:當創(chuàng)建派生類的對象時,413.向基類構造函數(shù)傳遞參數(shù)

如何向基類的構造函數(shù)傳遞參數(shù)呢?答案是使用向一個或多個基類的構造函數(shù)傳遞參數(shù)的派生類構造函數(shù)聲明的擴展格式即可。這種擴展的派生類構造函數(shù)聲明的一般格式為:

derived_constructor(arg_list):base1(arg_list),base2(arg_list), ┇ baseN(arg_list);{//bodyofderivedconstructor}

其中,base1到baseN是派生類繼承的基類名。注意,在有多個基類的情況下,用冒號將派生類的構造函數(shù)說明和基類分開,用逗號將基類分開。3.向基類構造函數(shù)傳遞參數(shù)42例3.9.2下面的例子使用了多個基類。

#include<iostream.h>classbase1{protected:inti;public:base1(intx){i=x;cout<<”Constructingbase1\n”;}//基類1的有參構造函數(shù)~base1(){cout<<”Destructingbase1\n”;}};classbase2{protected:intk;public:base2(intx){k=x;cout<<”Constructingbase2\n”;}//基類2的有參構造函數(shù)~base2(){cout<<”Destructingbase2\n”;}};例3.9.2下面的例子使用了多個基類。43classderived:publicbase1,publicbase2{intj;public:derived(intx,inty,intz):base1(y),base2(z)//derived使用x,y,z傳遞參數(shù)給基類構造函數(shù){j=x;cout<<”Constructingderived\n”;}~derived(){cout<<”Destructingderived\n”;}voidshow(){cout<<i<<””<<j<<””<<k<<”\n”;}};main(){derivedob(3,4,5);//定義類derived的對象obob.show(); //顯示435return0;}Constructingbase1Constructingbase2Constructingderived435DestructingderivedDestructingbase2Destructingbase1運行結果classderived:publicbase1,pub441.多態(tài)性(polymorphism)

多態(tài)性指的是一個接口名稱具有多種功能,是面向?qū)ο蟪绦蛟O計的重要特性之一。C++有兩種多態(tài)性,一是靜態(tài)的多態(tài)性,一是運行時的多態(tài)性。所謂靜態(tài)的多態(tài)性,是指操作作用的確切對象是在運行之前(即編譯時)就能確定的,所以相應的反應也是在運行之前就能確定的,這種多態(tài)性在C++中是用重載實現(xiàn)的。所謂運行時的多態(tài)性,是指操作作用的確切對象依賴于運行的進程,其相應的反應必須在運行時動態(tài)給出。C++是通過虛擬函數(shù)(virtualfunction)實現(xiàn)這種多態(tài)性的。

2.靜態(tài)聯(lián)編與動態(tài)聯(lián)編

聯(lián)編是指將函數(shù)調(diào)用與相應的函數(shù)體代碼彼此關聯(lián)的過程,若此過程在程序開始運行前的編譯階段完成,稱為靜態(tài)聯(lián)編。與靜態(tài)聯(lián)編不同,在程序運行時進行的聯(lián)編方式,稱為動態(tài)聯(lián)編。一般說來,動態(tài)聯(lián)編是通過指針來實現(xiàn)的。3.10多態(tài)性3.10多態(tài)性453.11重載1.函數(shù)重載(1)函數(shù)重載及其好處函數(shù)重載允許一個程序內(nèi)聲明多個名稱相同的函數(shù),這些函數(shù)可以完成不同的功能,并可以帶有不同類型、不同數(shù)目的參數(shù)及返回值。使用函數(shù)重載可以減輕用戶的記憶負擔,并使程序結構簡單、易懂。重載包含函數(shù)重載和操作符重載,是C++語言提供的一個重要特性。重載不僅為編譯時的多態(tài)性提供了大部分支持,而且使得語言具有很大的靈活性和易擴展性。3.11重載1.函數(shù)重載重載包含函數(shù)重載46#include<iostream.h>intAbs(inti);doubleAbs(doubled);longAbs(longl);//程序包含三個名為Abs的重載版本的函數(shù)main(){cout<<Abs(-10)<<”\n”;cout<<Abs(-12.0)<<”\n”;cout<<Abs(-7L)<<”\n”;return0;}intAbs(inti){cout<<“usingintegerAbs()\n”;returni<0?-i:i;}doubleAbs(doubled){cout<<“usingdoubleAbs()\n”;returnd<0.0?-d:d;}longAbs(longl){cout<<“usinglongAbs()\n”;returnl<0?-l:l;}#include<iostream.h>47(2)函數(shù)重載的基本規(guī)則重載函數(shù)時我們必須遵守一個基本規(guī)則:你提供給編譯程序的重載函數(shù)必須在它們的參數(shù)類型或參數(shù)數(shù)量上不同。

#include<iostream.h>intmyfunc(inti);intmyfunc(inti,intj); //重載函數(shù)具有不同數(shù)目的參數(shù)main(){cout<<myfunc(20)<<”\n”; //調(diào)用myfunc(inti)cout<<myfunc(3,4)<<”\n”; //調(diào)用myfunc(inti,intj)return0;}intmyfunc(inti){returni;}intmyfunc(inti,intj){returni*j;}(2)函數(shù)重載的基本規(guī)則48(3)重載成員函數(shù)在類的成員函數(shù)和構造函數(shù)上,也可以直接使用函數(shù)重載的概念。例如,假設你要寫兩個不同的函數(shù)來顯示一個窗口,一個函數(shù)要求提供大小作為一個參數(shù),另一個不要求參數(shù)但使用缺省尺寸??梢砸赃@種形式寫一對重載的成員函數(shù):voidDisplayWindow();voidDisplayWindow(CRectwinRect);創(chuàng)建完這些重載的成員函數(shù)之后,就可以調(diào)用任意一個。這個語句將調(diào)用第一個DisplayWindow函數(shù):

DisplayWindow();下面的語句將調(diào)用第二個DisplayWindow函數(shù):CRECTwinRect(10,10,50,200);DisplayWindow(winRect);(3)重載成員函數(shù)49(4)重載構造函數(shù)在C++中,構造函數(shù)經(jīng)常被重載。許多構造函數(shù)有兩個甚至更多的版本。classExample{ intx;public: Example(){x=0;} //定義重載的構造函數(shù) Example(inta){x=a;}voiddisplay();};┇定義重載的構造函數(shù)后,聲明對象時就可以根據(jù)不同的參數(shù)來分別調(diào)用不同的構造函數(shù)。例如:voidmain(){ExampleA; //自動調(diào)用構造函數(shù)Example()ExampleB(3); //自動調(diào)用構造函數(shù)Example(inta)┇}#include<iostream.h>#include<stdio.h>classdate{intday,month,year;public:date(char*d);date(intm,intd,inty);voidshow_date();};date::date(char*d) //用字符串初始化{sscanf(d,”%d%*c%d%*c%d”,&month,&day,&year);}date::date(intm,intd,inty) //用整數(shù)初始化{day=d;month=m;year=y;}voiddate::show_date(){cout<<month<<”/”<<day;cout<<”/”<<year<<”\n”;}main(){dateob1(3,6,2000),ob2(”10/21/1999”);ob1.show_date();ob2.show_date();return0;}mm/dd/yyyymain(){chars[80];cout<<”Enternewdate:”;cin>>s;dated(s);d.show_date();return0;}(5)派生類中的重載函數(shù)#include<iostream.h>classAclass{private:intaVal;public:Aclass(){}~Aclass(){}intValue(intn){aVal=n+1;returnaVal;}};classBclass{private:floatbVal;public:intValue(floatn){bVal=n+2;returnbVal;}};intmain(){Bclassanob;cout<<anob.Value(100)<<’\n’;return0;}(6)作用域操作符intmain(){Bclassanobject;cout<<anobject.Aclass::Value(100)<<’\n’;//使用作用域操作符來調(diào)用Aclass::Value()return0;}2.操作符重載(1)編寫操作符重載函數(shù)函數(shù)類型operator#(形參表){//函數(shù)體}(2)操作符重載函數(shù)的作用域Moneyoperator+(int){//函數(shù)體}(3)C++如何實現(xiàn)操作符重載(5)操作符重載舉例AClass.operator++();AClassAClass::operator++(){//bodyoffunction}++aObject;#include<iostream.h>#include<math.h>#include<stdlib.h>#include<stdio.h>classMoney{private:doubledollars;doublecents;public:Money(){} //定義構造函數(shù)~Money(){} //定義析構函數(shù) Money(doubled,doublec); //另一構造函數(shù)Money(double); //從double轉(zhuǎn)換Moneyoperator++(); //操作符重載doubleGetAmount(double&n);};MoneyMoney::operator++(){cents++;if(cents>99){dollars++;cents=0;}return*this;}Money::Money(doubled,doublec){dollars=d;cents=c;}Money::Money(doublecash) //一個轉(zhuǎn)換構造函數(shù){ //將浮點值轉(zhuǎn)換成Money值doublefrac,n; frac=modf(cash,&n); //一個math.h函數(shù)cents=frac*100;dollars=n;}doubleMoney::GetAmount(double&n){n=dollars;returncents;}intmain(){doublec,d;MoneymyCash(7.99);c=myCash.GetAmount(d);cout<<d<<"dollars\n";cout<<c<<"cents\n";++myCash;c=myCash.GetAmount(d);cout<<d<<"dollars\n";cout<<c<<"cents\n";return0;}7dollars99cents8dollars0centsMoneyoperator++();Moneyoperator++(intx);MoneyMoney::operator++(intx){cents++;if(cents>99){dollars++;cents=0;return*this;}}(4)重載構造函數(shù)50(4)重載構造函數(shù)在C++中,構造函數(shù)經(jīng)常被重載。許多構造函數(shù)有兩個甚至更多的版本。classExample{ intx;public: Example(){x=0;} //定義重載的構造函數(shù) Example(inta){x=a;}voiddisplay();};┇

定義重載的構造函數(shù)后,聲明對象時就可以根據(jù)不同的參數(shù)來分別調(diào)用不同的構造函數(shù)。voidmain(){ExampleA; //自動調(diào)用構造函數(shù)Example()ExampleB(3); //自動調(diào)用構造函數(shù)Example(inta)┇}(4)重載構造函數(shù)定義重載的構造函數(shù)后,聲明51例:下面的程序創(chuàng)建了一個叫做date的類,它表示一個公歷日期。

#include<iostream.h>#include<stdio.h>classdate{intday,month,year;public:date(char*d);date(intm,intd,inty);voidshow_date();};date::date(char*d) //用字符串初始化{sscanf(d,”%d%*c%d%*c%d”,&month,&day,&year);}例:下面的程序創(chuàng)建了一個叫做date的類,它表示一個公歷日期52date::date(intm,intd,inty) //用整數(shù)初始化{day=d;month=m;year=y;}voiddate::show_date(){cout<<month<<”/”<<day;cout<<”/”<<year<<”\n”;}main(){dateob1(3,6,2000),ob2(”10/21/1999”);ob1.show_date();ob2.show_date();return0;}date::date(intm,intd,inty53(5)派生類中的重載函數(shù)在類繼承中,也可以出現(xiàn)基類的成員函數(shù)和派生類的成員函數(shù)名字相同的情形。這時,在派生類中說明的任何重載超越在基類中說明的函數(shù)。

#include<iostream.h>classAclass{private:intaVal;public:Aclass(){}~Aclass(){}intValue(intn){aVal=n+1;returnaVal;}};classBclass{private:floatbVal;(5)派生類中的重載函數(shù)54public:intValue(floatn){bVal=n+2;returnbVal;}};intmain(){Bclassanob;cout<<anob.Value(100)<<’\n’;return0;}

上例中,名為Bclass的類從Aclass類中派生出來。Aclass的定義中包含了一個名為Value的函數(shù)。

public:上例中,名為Bclass的類從55(6)作用域操作符

如果由派生類說明的成員函數(shù)超越了由基類說明的成員函數(shù),那么可以用作用域操作符(::)的指引來訪問在基類中說明的成員函數(shù)。

例:可以用下面的main()函數(shù)來代替上例中的main()函數(shù)。

intmain(){Bclassanobject;cout<<anobject.Aclass::Value(100)<<’\n’;//使用作用域操作符來調(diào)用Aclass::Value()return0;}101運行結果(6)作用域操作符101運行結果562.操作符重載操作符重載和函數(shù)重載功能一致。通過操作符重載,可以重新定義C++語言中的已有操作符的功能,使得它們能針對不同的情況執(zhí)行不同的操作。操作符重載使得程序員可把C++操作符的定義擴展到操作數(shù)是對象的情況。

(1)編寫操作符重載函數(shù)函數(shù)類型operator#(形參表){//函數(shù)體}

其中,operator是關鍵字(所以有時也稱操作符重載函數(shù)為operator函數(shù)),#表示欲定義的操作符,函數(shù)類型指明返回值類型,通常與類類型一致或為void類型。2.操作符重載57(2)操作符重載函數(shù)的作用域

當重載一個操作符時,普通的作用域規(guī)則也適用,操作符被重載的作用范圍就是重載它的函數(shù)出現(xiàn)的作用范圍。

Moneyoperator+(int){//函數(shù)體}(2)操作符重載函數(shù)的作用域58(3)C++如何實現(xiàn)操作符重載在C++語言中,操作符只能對屬于固有類型的常量和變量進行操作。而且,C語言中操作符的含義是固定的。在C++中你可以根據(jù)自己的意圖定義操作符。當你重定義一個操作符時,你可以用代碼記號來表達對用戶自定義類的操作。當C++編譯程序?qū)σ粋€表達式進行求值時,它會檢查一系列的與操作符號混在一起的值(包括常量和變量)。當遇到一個操作符時,它首先判斷此操作符是用作一元或者是二元操作符。然后,編譯程序根據(jù)優(yōu)先規(guī)則和組織規(guī)則對此表達式求值,同時根據(jù)這些規(guī)則要求給操作符和操作數(shù)分組。編譯程序判定它遇到的操作符的操作數(shù)據(jù)的類型。只有在那時,它才知道此表達式是否合法,而且如果合法,則應當產(chǎn)生什么代碼。(3)C++如何實現(xiàn)操作符重載59例:重載一元操作符++,用來遞增Money類的值。例中Money類用來存放錢數(shù),它包含兩個雙精度的成員變量。一個成員變量用于存儲結果的元值,另一個用于存儲結果的分值。#include<iostream.h>#include<math.h>#include<stdlib.h>#include<stdio.h>classMoney{private: doubledollars; doublecents;public: Money(){} //定義構造函數(shù) ~Money(){} //定義析構函數(shù) Money(doubled,doublec); //另一構造函數(shù)Money(double); //從double轉(zhuǎn)換 Moneyoperator++(); //操作符重載 doubleGetAmount(double&n);};例:重載一元操作符++,用來遞增Money類的值。例中Mon60MoneyMoney::operator++(){ cents++; if(cents>99) { dollars++; cents=0; } return*this;}Money::Money(doubled,doublec){ dollars=d;cents=c;}Money::Money(doublecash) //一個轉(zhuǎn)換構造函數(shù){ //將浮點值轉(zhuǎn)換成Money值 doublefrac,n; frac=modf(cash,&n); //一個math.h函數(shù)cents=frac*100;dollars=n;}MoneyMoney::operator++()61doubleMoney::GetAmount(double&n){ n=dollars; returncents;}intmain(){ doublec,d; MoneymyCash(7.99);

c=myCash.GetAmount(d); cout<<d<<"dollars\n"; cout<<c<<"cents\n";

++myCash;c=myCash.GetAmount(d); cout<<d<<"dollars\n";cout<<c<<"cents\n";return0;}7dollars99cents8dollars0cents

運行結果doubleMoney::GetAmount(double62例:重載加法操作符,使其將兩個Money類的值相加并將結果存在一個Money對象中

。#include<iostream.h>#include<math.h>#include<stdlib.h>classMoney{private: doubledollars; doublecents;public: Money(){} //定義構造函數(shù) ~Money(){} //定義析構函數(shù) Money(doubled,doublec); //另一構造函數(shù)Money(double); //轉(zhuǎn)換構造函數(shù) Moneyoperator+(Moneym); //操作符重載doubleGetAmount(double&n);};例:重載加法操作符,使其將兩個Money類的值相加并將結果存63MoneyMoney::operator+(Moneym){ cents+=m.cents; dollars+=m.dollars; if(cents>99) { dollars=dollars+1; cents=cents-100; } return*this;}Money::Money(doubled,doublec){ dollars=d;cents=c;}Money::Money(doublecash) //一個轉(zhuǎn)換構造函數(shù){ //將浮點值轉(zhuǎn)換成Money值 doublefrac,n; frac=modf(cash,&n); //一個math.h函數(shù)cents=frac*100;dollars=n;}MoneyMoney::operator+(Moneym64doubleMoney::GetAmount(double&n){ n=dollars; returncents;}intmain(){ doublec,d; MoneymyCash(3.49); MoneyyourCash(50.86); myCash=myCash+yourCash; c=myCash.GetAmount(d); cout<<"Younowhave"<<d<<"dollars.\n"; cout<<"Youalsohave"<<c<<"cents.\n"; return0;}Younowhave54dollars.Youalsohave35cents.

運行結果doubleMoney::GetAmount(double651.多態(tài)性與虛擬函數(shù)

C++的多態(tài)性是通過虛擬函數(shù)來實現(xiàn)的,而虛擬函數(shù)是基于繼承的環(huán)境中。在繼承關系下,派生類作為基類的子類,在任何要求基類對象的地方使用派生類對象是有意義的。我們可以用基類指針通過間接或直接的方式指向它的任何派生類的對象。當通過一個基類指針引用一個派生類對象時,只能調(diào)用基類所定義的成員函數(shù),而無法調(diào)用派生類定義的成員函數(shù),即使派生類重新定義了基類的成員函數(shù),所調(diào)用的仍是基類中的而不是派生類中的成員函數(shù)。當通過指針引用一個對象時,指針的類型決定了可以調(diào)用的成員函數(shù)。

3.12虛擬函數(shù)3.12虛擬函數(shù)66#include<iostream.h>classPerson{public: voidDisplay(){cout<<“classPerson\n”;}};classChild:publicPerson{public:voidDisplay(){cout<<”classChild\n”;}};classOld:publicPerson{public:voidDisplay(){cout<<”classold\n”;}};voidmain(){Personpeople1;Person*p;Childpeople2;Oldpeople3;p=&people1;p->Display();p=&people2;p->Display();p=&people3;p->Display();}

classPersonclassPersonclassPerson運行結果#include<iostream.h>public:cl67

修改上面的例子,將基類的成員函數(shù)Display()聲明為虛擬函數(shù)。#include<iostream.h>classPerson{public: virtualvoidDisplay() //聲明基類的成員函數(shù)為虛擬函數(shù){cout<<“classPerson\n”;}}; //定義基類PersonclassChild:publicPerson{public:voidDisplay(){cout<<”classChild\n”;}}; //定義派生類Child修改上面的例子,將基類的成員函數(shù)Display(68classOld:publicPerson{public:voidDisplay(){cout<<”classold\n”;}}; //定義派生類Oldvoidmain(){Personpeople1;Person*p; //定義基類指針pChildpeople2;Oldpeople3;p=&people1; //基類指針指向基類對象people1p->Display(); //調(diào)用基類Person的成員函數(shù)Display()p=&people2; //基類指針指向基類對象people2p->Display(); //調(diào)用派生類Child的成員函數(shù)Display()p=&people3; //基類指針指向基類對象people3p->Display(); //調(diào)用派生類Old的成員函數(shù)Display()}cl

溫馨提示

  • 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

提交評論