版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第3章面向?qū)ο缶幊?.1綜述3.2類與對象3.3繼承與派生3.4多態(tài)性3.5類、繼承與派生、多態(tài)性綜合實例思考題
3.1綜述
面向?qū)ο蟮某绦蛟O(shè)計(Object-OrientedProgramming,OOP)以分析真實世界為出發(fā)點,與其他設(shè)計概念相比更接近人類處理問題的一般方法。封裝性、繼承性和多態(tài)性是OOP的三個特征,本章將針對這三個特征來學(xué)習(xí)面向?qū)ο缶幊?,使讀者掌握類、對象、繼承、虛函數(shù)等基本概念,為后續(xù)內(nèi)容的學(xué)習(xí)打下基礎(chǔ)。
通常我們認為VisualC++就是面向?qū)ο?。其實,VisualC++是一個基于VisualC語言的程序語言,然后加上支持面向?qū)ο蟾拍顧C制而成為面向?qū)ο蟮某绦蛘Z言。因此,VisualC++并不是一個純粹的面向?qū)ο蟮恼Z言,而現(xiàn)在流行的另一種語言——JAVA才是一個純粹面向?qū)ο蟮恼Z言。我們總是把世界看做對象的集合。例如,把飛機看作一個對象而不是一個發(fā)動機,不同形狀的金屬片和一些電纜之類的東西;看見一只活潑可愛的小貓,沒人把它當作是皮毛包裹的骨頭、肌肉和內(nèi)臟器官。在這里,小貓是一個實例,是生物學(xué)樹狀結(jié)構(gòu)中某一種類的一個對象。擴展開來,對象其實就是東西,也就是周圍的一切有形或無形的東西。
建立了對象的思想后,我們將其運用到編程當中。面向?qū)ο蟮某绦蛟O(shè)計的本質(zhì)在于用面向?qū)ο蟮母拍钊ふ摇⒎治龀霈F(xiàn)實世界中對象與對象之間的關(guān)系,然后運用程序語言模擬這些現(xiàn)實世界的對象,最后完成電腦系統(tǒng)的建構(gòu)。
面向?qū)ο蟮某绦蛟O(shè)計有三個基本原則——封裝性、繼承性和多態(tài)性,下面分別進行講解。
1.封裝性
一個面向?qū)ο蟮恼Z言必須提供一種能夠把與對象相關(guān)的所有信息封裝到對象自身中的機制,即封裝性。
封裝機制允許把一個對象中的各個獨立的元素——變量和函數(shù)定義看待成一個整體,而無需考慮對象內(nèi)部的具體結(jié)構(gòu)。現(xiàn)實生活中有很多關(guān)于封裝的例子。例如,電視機是一個對象,我們使用時只需要它能夠播放電視節(jié)目,完全不必關(guān)注它是等離子電視或液晶電視。又如集成電路芯片,我們在使用時只需要了解它的各個引腳的功能而無需了解它內(nèi)部的連接線路。事實上,通過使用對象的方法或者成員函數(shù),可以完全不必知道對象中的屬性或者變量的標識符。
2.繼承性
語言必須提供一種方法,讓程序可以使用對象的定義來創(chuàng)建一個新的對象,即繼承性。
繼承性提高了軟件的再利用率。怎么理解呢?例如,狗是一種哺乳類動物,狗具有哺乳類動物的所有特性——會哺乳。狗除了具有哺乳類動物的共性之外,也有自己的特性,否則所有其他的哺乳類動物都可以被稱為“狗”。因此狗類會再定義狗特有的特性,比如:愛啃骨頭、叫聲為“汪汪”、會搖尾巴等。到此為止,還看不出繼承的好處。如果有一天要擴充程序,增加對貓的模擬,在建立一個貓類時,其優(yōu)點就體現(xiàn)出來了。因為貓也是哺乳類動物,所以貓類也應(yīng)該繼承于哺乳類動物。此時,不需再次編寫描述貓類中哺乳類動物的特性的代碼,只要將貓類繼承于哺乳類動物即可。因此,在狗、貓類里,都不需要描述它們共同具備的會哺乳類特性,這就再利用了定義哺乳類動物的程序代碼。同樣貓類的特性,如會抓老鼠,則必須在貓類里定義。
3.多態(tài)性
必須要有一種方法可以修改新對象的行為,即使它是從已經(jīng)存在的對象中派生的。這種特性即稱為多態(tài)性。
多態(tài)性是指一個對象既可以繼承父輩的特點,也可以有它自己的屬性和方法,甚至還可以修改從父輩繼承的行為。我們生活中有很多多態(tài)性的例子?;瘜W(xué)中的“同素異形體”,同樣都是碳,煤炭可以燃燒,用于取暖和作為燃料;而鉆石,則是另一種完全不同的性質(zhì)。汽車是繼承于“車輛”類中的,車輛的一個屬性就是能夠自動推進,并能夠滑行。汽車繼承了這些屬性,但它重新定義了推進方法,并且聲明了它必須用四個輪子來完成運動,而不是兩個輪子。由于多態(tài)性,每個對象可以有獨特的表現(xiàn)方式。使用多態(tài)性,同一函數(shù)對于一個對象有一種表現(xiàn)方式,而對于另一個對象有另一種表現(xiàn)方式。
3.2類與對象
3.2.1類和對象的含義
類和對象是VisualC++語言中的兩個重要的概念。
1.類
類可以被看成是一些對象的特性描述,即對某種對象的抽象描述。C++語言中提供了類這種工具使得應(yīng)用中的實體(對象)在程序中可以直接地被表示為一個標識符,并且可以對它進行引用和操作。
例如,貓是一種動物,你家里養(yǎng)了一只叫美麗的貓。如果寫一個模擬貓的程序,程序中一定要有一個貓類,里面有貓的特性,比如:貓有四條腿、貓有毛、貓“咪咪”叫、貓走路爪子會收起來,貓愛吃魚,等等。當要用這個程序來模擬家里的美麗時,就要用貓類來生成一只名叫美麗的對象。因此,我們可以把類看成是建立對象的模型,當在程序中建立一個對象時,就必須以類里的特性描述作為模型,產(chǎn)生一個對象,而這個對象就具有這幾個類的屬性與方法。所以,某一對象只有一個類,但類的對象可以有好幾個,建立的對象都具有其類的所有特性,就像一個模子可以做出好多個零件一樣。
類是用來確定一類對象的行為的,而這些行為是通過類的內(nèi)部數(shù)據(jù)結(jié)構(gòu)和相關(guān)的操作來確定的。類和對象的關(guān)系就是抽象(貓類)和具體(美麗)的關(guān)系。類里應(yīng)該包含對類的靜態(tài)屬性的描述——稱為數(shù)據(jù)成員變量的描述,如貓有四條腿,一個腦袋,一條尾巴,身披毛發(fā)等,以及動態(tài)屬性的描述——由稱為成員函數(shù)的函數(shù)來描述,如貓看到老鼠會去抓,看到魚會“咪咪”叫等。
2.類的聲明
類的聲明格式一般分為說明部分和實現(xiàn)部分。說明部分用來說明該類中的成員,包含數(shù)據(jù)成員的說明和成員函數(shù)的說明。實現(xiàn)部分是對成員函數(shù)的定義。概括說來,說明部分將告訴使用者“做什么”,而實現(xiàn)部分是告訴使用者“怎么做”。
類的聲明以關(guān)鍵字class開始,后面跟隨類的名字,如狗、貓、汽車等抽象的名稱。
一般的形式如下:
class類名稱//關(guān)鍵字,類名稱是一種標識符。
{
public:
數(shù)據(jù)成員或成員函數(shù)的說明;
private:
數(shù)據(jù)成員或成員函數(shù)的說明;
protected:
數(shù)據(jù)成員或成員函數(shù)的說明;
};
<成員函數(shù)的實現(xiàn)>
這里有幾點需要說明:
(1)?class是定義類的關(guān)鍵字,類名稱是一種標識符,一般第一個字母大寫,如Dog、Cat、Chair等。
(2)大括號內(nèi)是類的說明部分,說明該類的數(shù)據(jù)成員或成員函數(shù),末尾的分號不能省。關(guān)鍵字private、protected、public表征類中數(shù)據(jù)成員和函數(shù)的訪問權(quán)限。
(3)關(guān)鍵字public、private和protected在類體內(nèi)出現(xiàn)的先后順序無關(guān),并且允許多次出現(xiàn),用它們來說明類成員的訪問權(quán)限。缺省的訪問權(quán)限是私有的(private)。
(4)<成員函數(shù)的實現(xiàn)>是類定義中的實現(xiàn)部分,這部分包含所有在類體內(nèi)說明的函數(shù)的定義。如果一個成員函數(shù)在類體內(nèi)定義了,實現(xiàn)部分將不出現(xiàn)。
(5)如果所有的成員函數(shù)都在類體內(nèi)定義了,則實現(xiàn)部分可以省略。
3.類成員的訪問權(quán)限
1)公有類型(public)
公有類型允許對函數(shù)或者變量的訪問,它們是類與外部的接口,任何外部函數(shù)都可以訪問公有類型的數(shù)據(jù)成員或函數(shù)。
2)保護類型(protected)
保護類型的訪問級別比較嚴格,只有類、派生類的成員函數(shù)可以訪問。保護類型仿佛將函數(shù)或數(shù)據(jù)成員安放在一道安全的墻壁之后,只有那些特定的類才能打開它們。
3)私有類型(private)
私有類型給數(shù)據(jù)成員和函數(shù)最嚴密的保護,只有成員函數(shù)才能修改私有變量或執(zhí)行私有函數(shù)。通常類中聲明的數(shù)據(jù)和函數(shù)如果沒有特別指明,都視為私有類型。公有類型就像集成芯片的引腳和芯體,對外界是可見的;私有類型就像芯片中的電路,對外界是不可見的。
4.類的建立舉例
classStudent //說明這是一個名為Student的類
{
private:
intage; //成員變量
charsex; //成員變量
charname[20]; //成員變量
public:
voidregist(char*name,intage,charsex);//輸入個人信息成員函數(shù)
char*getname(); //得到姓名成員函數(shù)
intgetage(); //得到年齡成員函數(shù)
chargetsex(); //得到性別成員函數(shù)
voidshowme(); //顯示學(xué)生信息成員函數(shù)
};//類定義完畢過以上的語句就定義了一個名為Student的類,其屬性包括姓名、年齡、性別,成員函數(shù)包括輸入個人信息、得到姓名、得到年齡、得到性別、顯示學(xué)生信息。3.2.2對象
如果說類是抽象的,那么對象則是類的實例,也就是說對象總屬于某個已知的類。因此,在定義對象之前,一定要先定義好該對象所屬的類。
對對象的聲明可以在聲明類時直接定義對象,也可以在聲明類后再單獨聲明對象。
對象的聲明方法如下:
<類名稱><對象名稱>;
也可以定義指向類的指針:
<類名稱><*指針變量名>;
我們可以定義Student類的兩個對象,student1和student2,一個用對象名稱聲明,一個用指針變量聲明。
Studentstudent1,*student2;
對象聲明后就可以使用,通過對象可以訪問類中的公有數(shù)據(jù)成員和成員函數(shù),訪問的方法為:
<對象名稱>.<成員>
如果使用指向類的指針方式,則訪問的方法為:
<指針變量名>→<成員>
或
<*指針變量名>.<成員>
在使用對象時,就可以調(diào)用類中的成員,比如:
student1.getname();
student2→showme();
(*student2).getsex();
注意:如果企圖執(zhí)行,則是錯誤的,因為name數(shù)據(jù)成員是private類型,對外界是不可見、不可訪問的。3.2.3構(gòu)造函數(shù)和析構(gòu)函數(shù)
構(gòu)造函數(shù)與析構(gòu)函數(shù)是類的兩個特殊的成員函數(shù)。
1.構(gòu)造函數(shù)
在創(chuàng)建了一個對象后,需要對該對象的數(shù)據(jù)成員進行初始化。VisualC++允許通過一個專門的函數(shù)——構(gòu)造函數(shù)來自動完成這些工作。如果沒有在類的定義中聲明它,編譯器也會生成一個空的構(gòu)造函數(shù)。構(gòu)造函數(shù)沒有返回值,甚至連void類型的返回值都沒有,如果企圖為構(gòu)造函數(shù)添加返回值,則會導(dǎo)致編譯器報錯。
構(gòu)造函數(shù)是由用戶定義的,它必須與類名同名,以便系統(tǒng)能識別它并把它作為構(gòu)造函數(shù)。構(gòu)造函數(shù)的特點如下:
(1)構(gòu)造函數(shù)是成員函數(shù),函數(shù)體可寫在類體內(nèi),也可寫在類體外。
(2)構(gòu)造函數(shù)是一個特殊的函數(shù),該函數(shù)的名字與類名相同,一般聲明為public函數(shù),無返回值,不指定類型,也不需要加void類型聲明。
(3)程序中不能直接調(diào)用構(gòu)造函數(shù),在創(chuàng)建對象時系統(tǒng)自動調(diào)用構(gòu)造函數(shù)。
構(gòu)造函數(shù)的聲明格式為:
類名(形式參數(shù))
{
函數(shù)體;
}
2.析構(gòu)函數(shù)
析構(gòu)函數(shù)與構(gòu)造函數(shù)功能相反,當對象所在的函數(shù)已調(diào)用完畢,系統(tǒng)自動執(zhí)行析構(gòu)函數(shù),并將對象占用的資源釋放。
析構(gòu)函數(shù)的特點:
(1)析構(gòu)函數(shù)也是成員函數(shù),函數(shù)體可寫在類體內(nèi),也可以寫在類體外。
(2)析構(gòu)函數(shù)的名字同類名,并在前面加“~”字符,以與構(gòu)造函數(shù)區(qū)別。析構(gòu)函數(shù)不指定數(shù)據(jù)類型,并且也沒有參數(shù)。
(3)一個類中只可能定義一個析構(gòu)函數(shù),不能重載。
(4)如果用戶沒有編寫析構(gòu)函數(shù),編譯系統(tǒng)會自動生成一個缺省的析構(gòu)函數(shù)。析構(gòu)函數(shù)的聲明格式為:
類名()
{
函數(shù)體
}
例如,對類Student建立其構(gòu)造函數(shù)和析構(gòu)函數(shù)的方法為:
classStudent//說明這是一個名為Student的類
{
private:
…
public:
…
Person()//構(gòu)造函數(shù)
{ cout<<"這是構(gòu)造函數(shù)"<<endl;
}
~Person()//析構(gòu)函數(shù)
{
cout<<"這是析構(gòu)函數(shù)"<<endl;
}
}; //類定義完畢
如果在主函數(shù)main()中聲明Student類的一個對象,則程序為:
voidmain() //主函數(shù)
{
Personp1;//聲明Person類的一個對象p1
…
}其運行結(jié)果會在一開始就自動執(zhí)行構(gòu)造函數(shù),出現(xiàn)“這是構(gòu)造函數(shù)”的輸出;當我們對對象使用完畢后,為了釋放系統(tǒng)資源,系統(tǒng)會自動調(diào)用類的析構(gòu)函數(shù),出現(xiàn)“這是析構(gòu)函數(shù)”的輸出。3.2.4類的對象成員
當一個類中的數(shù)據(jù)成員是某一個類的一個對象時,就稱這種成員是新建類的子對象或者對象成員。
定義對象成員的方法為:
classX
{
類名1成員名1;
類名2成員名2;
類名n成員名n;
//其他成員
};
這里X為新建類的類名,類名1、類名2、…、類名n,必須為已定義過的類。如要將前述建立的Student類作為Person類,其方法為:
classStudent //說明這是一個名為Student的類
{
private:
intage; //成員變量
charsex; //成員變量
charname[20]; //成員變量
public:
voidregist(char*name,intage,charsex);//輸入個人信息成員函數(shù)
char*getname(); //得到姓名成員函數(shù)
intgetage(); //得到年齡成員函數(shù)
chargetsex(); //得到性別成員函數(shù)
voidshowme();
//顯示學(xué)生信息成員函數(shù)
}; //類定義完畢
classPerson
{
private:
…
Students; //定義一個Student類的成員變量s,作為B的對象成員
public:
…
protected:
…
…
}3.2.5成員函數(shù)
如果說成員變量說明類具有哪些基本的屬性,那么成員函數(shù)可以認為是類具有的具體功能。好比貓類除了具有年齡、身高、性別這些基本的量化屬性外,還會“咪咪”叫,見了耗子就抓等行為功能屬性,這些都用成員函數(shù)來實現(xiàn)。
成員函數(shù)的基本格式為:
(類型)類名::函數(shù)名(形式參數(shù))
{
函數(shù)體
}從基本格式中可以看出,除去“類名::”部分,與一般的函數(shù)定義沒有差別。由于C++中允許同一個函數(shù)名出現(xiàn)在不同的類中,如eat()函數(shù)既可以出現(xiàn)在Dog類中,也可以出現(xiàn)在Cat類中。顯然不同的類eat()包含不同的內(nèi)容。為了將同名成員函數(shù)進行區(qū)別,引入符號“::”,該符號叫做域運算符,它用來指定哪個函數(shù)屬于哪個類。
如:
voidCat::eat()或voidDog::eat()3.2.6*this指針
*this指針是一個指向當前被操作對象的特殊指針。每個成員函數(shù)都有一個this指針變量,在類的成員函數(shù)中*this指針代表當前對象。*this指針可以顯式使用也可以隱式使用。當定義一個類的對象時,該對象的成員均含有由系統(tǒng)自動生成的指向當前對象的this指針。
類中的成員函數(shù)可以直接訪問該類的其他成員,且同一個類的不同對象都共享同一組成員函數(shù)。當某個對象(設(shè)為A)調(diào)用其成員函數(shù)如MEM()時,如何保證MEM()(MEM()中有訪問其他成員的操作)所訪問的就是對象A的成員呢?這就要通過隱含的*this指針來確定。比如當對象A調(diào)用一個成員函數(shù)時,系統(tǒng)將自動為該函數(shù)指定一個隱含的參數(shù),該參數(shù)是一個指向?qū)ο驛的指針,這個指針就是*this指針。在實現(xiàn)成員函數(shù)的過程中,當訪問該對象的成員時,系統(tǒng)將自動使用這個隱含的指針。*this指針只允許在成員函數(shù)內(nèi)使用,不允許修改指針的值,但可以改變指針所指向數(shù)據(jù)的值。成員函數(shù)訪問類中成員變量的格式可以寫成:
this->成員變量3.2.7類與對象建立舉例
【例3-1】
建立一個名為Point的點類,具有x,y兩個坐標成員變量,并有其構(gòu)造函數(shù)和析構(gòu)函數(shù);再建立一個名為Rect的長方形類,有左上角和右下角兩個坐標成員變量,能計算長方形的寬度、長度和面積。在主函數(shù)中輸入正方形參數(shù),驗證是否正確。
操作步驟如下:
(1)打開VisualC++6.0。選擇“文件/新建”命令。
(2)在彈出的“新建”對話框中,單擊“工程”選項卡,其下選擇“Win32ConsoleApplication”項,在右邊的“工程”框中輸入工程名“chap3_1”,選擇保存位置后單擊按鈕,如圖3-1所示。圖3-1“新建“對話框
(3)在隨后彈出的“Win32ConsoleApplication-Step1of1”對話框中,選中,單擊按鈕,如圖3-2所示。圖3-2“Win32ConsoleApplication-Step1of1”對話框
(4)隨后彈出“新建工程信息”對話框,單擊按鈕。
(5)在項目工作區(qū)中,單擊選項卡,這時發(fā)現(xiàn)展開的文件夾里沒有文件,如圖3-3所示。圖3-3“ClassView”選項卡
(6)選擇“文件/新建”命令,彈出“新建”對話框。
(7)單擊“文件”選項卡,選擇“C++SourceFile”選項,在右邊“文件”下編輯框中輸入“chap3_1”,為新添加的C++源文件命名,單擊“確定”按鈕。
(8)在右邊出現(xiàn)了用戶輸入代碼的編輯區(qū),在其中輸入如下代碼:
#include"iostream.h"
classPoint //說明這是一個名為Point的類
{
public:
intx; //成員變量
inty; //成員變量
Point() //構(gòu)造函數(shù)
{
cout<<"這是Point構(gòu)造函數(shù)"<<endl;
}
~Point() //析構(gòu)函數(shù)
{
cout<<“這是Point析構(gòu)函數(shù)”<<endl;
}
};//類定義完畢
classRect //定義長方形類
{
public:
PointLefttop;
//建立類對象成員變量
PointRightbottom; //建立類對象成員變量
intgetlength()
//求長方形長成員函數(shù)
{ intlength;
length=Rightbottom.x-Lefttop.x;
returnlength;
}
intgetwide() //求長方形的寬成員函數(shù)
{
intwide;
wide=Rightbottom.y-Lefttop.y;
returnwide;
}
intsurface() //求長方形面積成員函數(shù)
{
return(Rightbottom.x-Lefttop.x)*(Rightbottom.y-Lefttop.y);
}
};voidmain()//主函數(shù)
{
Rectrect;
cout<<"請輸入左上角坐標"<<endl;
cin>>rect.Lefttop.x>>rect.Lefttop.y;
cout<<"請輸入右下角坐標"<<endl;
cin>>rect.Rightbottom.x>>rect.Rightbottom.y;
cout<<"長方形的長為:"<<rect.getlength()<<endl;
cout<<"長方形的寬為:"<<rect.getwide()<<endl;
cout<<"長方形的面積為:"<<rect.surface()<<endl;
}
(9)其運行結(jié)果如圖3-4所示。圖3-4建立類與對象運行結(jié)果
3.3繼?承?與?派?生
3.3.1繼承與派生的概念
C++語言中的繼承是類和類之間一種特殊關(guān)系的表示,是基于已存在的類創(chuàng)建新類的方法。類的繼承性是C++語言與C語言之間的最大不同,是OOP的重要特點之一。
在解釋繼承的意義前,仍然采用前面貓類和狗類繼承于哺乳動物的例子說明與繼承有關(guān)的名詞。
基類(baseclass):貓、狗類繼承于哺乳動物類,因此哺乳類就是貓、狗類的基類,也稱為父類。
派生類(derivedclass):在貓、狗類的例子里,貓、狗類就是繼承于哺乳類的派生類,也稱為子類,如圖3-5所示。圖3-5哺乳動物類層次圖繼承的概念來自于分類與遺傳。
人類習(xí)慣利用分類來管理與了解現(xiàn)實世界里的對象。以生物分類為例:界、門、綱等這些分類等級中,低層次的分類都具備其高層次分類的特性。
另一個理解繼承的概念來自于遺傳,每個人的特征或多或少都來自于父母的遺傳,但每個人都不可能完全與父親或母親一模一樣,有著自己的特征。
因此,在OOP里繼承使得派生類具有基類的特性,同時又允許在派生類的聲明時增加自己的特性,或修改基類的特性。基類派生類的關(guān)系如圖3-6所示。圖3-6基類派生類的關(guān)系一個派生類既可以從一個基類派生也可以從多個基類派生。從一個基類派生稱為單繼承,從多個基類派生稱為多重繼承。
派生類的構(gòu)造如下:
class派生類名:訪問方式基類名1,訪問方式基類名2,…,訪問方式基類名n
{
派生類中的新成員
};
其訪問方式可以為public(公有繼承),protected(保護繼承),private(私有繼承)任何一種,下面分別進行講解。
1.公有繼承
如果A類采用公有繼承方式繼承B類,A類將繼承B類的public成員與protected成員,且繼承后原成員函數(shù)的訪問級別不變。
2.保護繼承
如果A類采用保護繼承方式繼承B類,A類將繼承B類的public成員與protected成員,繼承后成員函數(shù)的訪問級別均為protected。
3.私有繼承
如果A類采用私有繼承方式繼承B類,A類將繼承B類的public成員與protected成員,繼承后成員函數(shù)的訪問級別均為private。如果沒有特別指明則為private方式。3.3.2繼承與派生的實例
【例3-2】建立一個名為Person的基類,其屬性包括年齡、性別、姓名和輸入信息及輸出信息成員函數(shù);建立一個名為School的基類,其屬性包括專業(yè)、學(xué)院和輸入信息及輸出信息成員函數(shù);再建立一個名為Student的繼承派生類,繼承Person類和School類,同時增加學(xué)號、成績輸入信息及輸出信息成員函數(shù);輸入相關(guān)信息,顯示其屬性。
操作步驟如下:
(1)如例3-1,建立一個“Aemptyproject”。
(2)為例3-2增加一個“C++ResourceFile”,文件名為“chap3_2”。
(3)在工作區(qū)中輸入代碼:#include"iostream.h"
#include"string.h"
classPerson //說明這是一個名為Person的類
{
public:
intage; //年齡數(shù)據(jù)
charsex; //性別數(shù)據(jù)
charname[20]; //姓名數(shù)據(jù)
voidshowp()
{
cout<<name<<""<<age<<""<<sex<<"";
}
};//類定義完畢
classSchool//說明這是一個名為Company的類
{
public:
charcollege[30]; //學(xué)院數(shù)據(jù)
charmajor[20]; //專業(yè)數(shù)據(jù)
voidshowc() //顯示公司信息
{
cout<<college<<“”<<major<<“”;
}
};
classStudent:publicPerson,publicSchool//Student類繼承于Person類和School類
{
public:
intID; //Student自己特有的數(shù)據(jù)成員--學(xué)號
intscore; //Student自己特有的數(shù)據(jù)成員--成績
voidshows() //顯示學(xué)生信息
{
cout<<ID<<""<<score<<""<<endl;
}
};
voidmain()
{
Students1; cout<<"請輸入你的姓名"<<endl;
cin>>;
cout<<"請輸入你的年齡"<<endl;
cin>>s1.age;
cout<<"請輸入你的性別"<<endl;
cin>>s1.sex;
cout<<"請輸入你的學(xué)院"<<endl;
cin>>s1.college;
cout<<"請輸入你的專業(yè)"<<endl;
cin>>s1.major;
cout<<"請輸入你的學(xué)號"<<endl;
cin>>s1.ID;
cout<<"請輸入你的成績"<<endl;
cin>>s1.score;
s1.showp();
s1.showc();
s1.shows();
}
(4)按“Ctrl+F5”鍵運行程序,按照提示輸入姓名、年齡、性別、學(xué)院、專業(yè)、學(xué)號、成績,執(zhí)行結(jié)果如圖3-7所示。圖3-7派生類Student具有Person類和School類的共同屬性,也有自己的特性該例中,派生類Student派生于Person類和School類,屬于多重繼承,具有Person類和School類的共性,如圖3-8所示。圖3-8Student繼承層次結(jié)構(gòu)
Student信息既包含作為獨立人的個人信息,也包含所在學(xué)校的信息。從上圖中可以看出,采用繼承方式可以體現(xiàn)出問題本身的層次。
在輸入Student信息中,調(diào)用了其基類成員變量并為其進行賦值。如果沒有采用繼承的方式,Student類中將重復(fù)輸入個人信息和學(xué)校信息的指令,增加了工作量。由此,繼承的主要作用體現(xiàn)在提高編程效率上。
在Student信息中,還添加了其基類中沒有的成員——
ID和score。其作為自身特有的成員,單獨寫在Student類中。
此例中,繼承的方式為public公有繼承方式,派生類可以訪問基類的所有public成員。
3.4多態(tài)性
函數(shù)重載和運算符重載是簡單的一類多態(tài)性。重要的多態(tài)性是建立在虛函數(shù)的概念和方法基礎(chǔ)之上的,下面重點講解。
3.4.1函數(shù)重載
函數(shù)重載就是賦給同一個函數(shù)名多個含義,其特點有如下兩個:
(1)?C++中允許在相同的作用域內(nèi)以相同的名字定義幾個不同的函數(shù),可以是成員函數(shù)也可以是非成員函數(shù)。
(2)定義重載函數(shù)要求函數(shù)的參數(shù)至少有一個類型不同,或者個數(shù)不同。重載函數(shù)的意義在于它可以用相同的名字訪問一組相互關(guān)聯(lián)的函數(shù),由編譯程序來進行選擇,這將有助于解決程序復(fù)雜性問題。
函數(shù)的返回類型對確定重載函數(shù)沒有意義,因為在沒有確定一個函數(shù)要調(diào)用哪個重載函數(shù)之前,函數(shù)的返回類型也是不確定的。當然,如果確定調(diào)用某個重載函數(shù),則函數(shù)調(diào)用表達式的類型也就被惟一地確定下來。
【例3-3】
建立一個類Reload,為output成員函數(shù)配置不同的輸入形式參數(shù),實現(xiàn)函數(shù)重載。
操作步驟如下:
(1)建立一個名為“chap3_3”的“Aemptyproject”。
(2)增加一個“C++ResourceFile”,文件名為“chap3_3”。
(3)在工作區(qū)中輸入代碼:
#include"iostream.h"
classReload //定義Reload類
{
public:
voidoutput(inti) //定義帶一個整型形式參數(shù)的output函數(shù)
{
cout<<i<<endl;
}
voidoutput(doublef) //定義帶一個浮點型形式參數(shù)的output函數(shù)
{
cout<<f<<endl;
} voidoutput(char*s)
//定義帶一個字符形指針參數(shù)的output函數(shù)
{
cout<<s<<endl;
}
voidoutput(char*s,intn)//定義帶兩個形式參數(shù)的output函數(shù)
{
cout<<s<<""<<n<<endl;
}
};
voidmain()//主函數(shù)
{
Reloadr;//定義一個A類對象a
r.output(6);//調(diào)用形式參數(shù)為整型的output函數(shù)
r.output(56.9);//調(diào)用形式參數(shù)為浮點型的output函數(shù)
r.output(“helloworld”);//調(diào)用形式參數(shù)為字符指針型的output函數(shù)
r.output(“helloworld",10);//調(diào)用形式參數(shù)為兩個的output函數(shù)
}
(4)按“Ctrl+F5”鍵,運行程序,執(zhí)行結(jié)果如圖3-9所示。
在A類里定義了4個同名的成員函數(shù)output,前三個靠參數(shù)類型進行識別,而最后一個函數(shù)則依靠參數(shù)個數(shù)進行區(qū)別。圖3-9形式參數(shù)不同的函數(shù)重載運行結(jié)果需要注意的是,在類中不能進行下述形式的重載聲明:
classReload
{
public:voidoutput(char*s)
{
cout<<s<<endl;
}
voidoutput(char*s,intn=10)
{
cout<<s<<""<<n<<endl;
}
};如果使用“r.output(“Welcomeyou”);”,則會發(fā)生邏輯混亂,造成調(diào)用時的二義性,無法惟一確定調(diào)用的是哪個重載函數(shù)。因此,不會出現(xiàn)期望的輸出結(jié)果,編譯過程中會出現(xiàn)如下報錯信息:
這種缺省參數(shù)的形式應(yīng)避免。3.4.2靜態(tài)聯(lián)編與動態(tài)聯(lián)編
由于函數(shù)重載的存在,當程序中出現(xiàn)調(diào)用同名函數(shù)時,編譯器會根據(jù)函數(shù)的參數(shù)類型、個數(shù)決定調(diào)用哪一個同名函數(shù)的代碼。這種把一個函數(shù)的調(diào)用與適當?shù)暮瘮?shù)代碼聯(lián)系在一起的過程叫做聯(lián)編。
按照聯(lián)編所進行的階段不同,可分為兩種不同的聯(lián)編方法,即靜態(tài)聯(lián)編和動態(tài)聯(lián)編。
1.靜態(tài)聯(lián)編
靜態(tài)聯(lián)編是在程序編譯階段確定一個函數(shù)調(diào)用與函數(shù)代碼間的對應(yīng)關(guān)系,這種對應(yīng)關(guān)系確定以后,在程序運行過程中就根據(jù)這個對應(yīng)關(guān)系去調(diào)用并執(zhí)行相關(guān)的函數(shù)代碼,并且這種對應(yīng)關(guān)系在程序運行過程中保持不變,下面我們先通過一個例子來看看靜態(tài)聯(lián)編的效果。
【例3-4】
建立一個基類Point,具備屬性包括X、Y坐標和求面積公式;再建立一個派生類Rectangle,具備屬性為長、寬、四個角的坐標及求面積計算公式,計算輸入坐標后矩形的面積。操作步驟如下:
(1)建立一個名為“chap3_4”的“Aemptyproject”。
(2)為例3-4增加一個“C++ResourceFile”,文件名為“chap3_4”。
(3)在工作區(qū)中輸入代碼:
#include"iostream.h"
#include"math.h"
classPoint//點類
{
private:
doublex,y;public:
Point(inti,intj)
{
x=i;
y=j;
}
doublearea()
{
return0.0;
}
};
classTriangle:publicPoint//基類為Point類的派生類?-?直角三角形類
{
private:
floatbottom,height;public:
Triangle(inti,intj,intk,intl,intm,intn);//構(gòu)造函數(shù)輸入直角三角形三點坐標
doublearea()
{
return0.5*bottom*height;
}
};
Triangle::Triangle(inti,intj,intk,intl,intm,intn):Point(i,j)//初始化Point參數(shù)并計算矩形寬、高
{
bottom=m-k;
height=l-j;
}voidfun(Point&s)
{
cout<<s.area()<<endl;
}
voidmain()
{
Triangletri(10,10,10,50,100,50);//初始化矩形參數(shù)
fun(tri);//調(diào)用函數(shù)fun求面積
}
(4)按“Ctrl+F5”鍵運行程序,執(zhí)行結(jié)果如圖3-10所示。圖3-10靜態(tài)聯(lián)編執(zhí)行結(jié)果為何結(jié)果不是期望的三角形面積?這是因為在fun()函數(shù)中,s所引用的對象執(zhí)行的area()操作被關(guān)聯(lián)到Point::area()的代碼上。在程序編譯階段,對s引用的對象所執(zhí)行的area()操作只能約束到Point類的函數(shù)上,因此輸出結(jié)果為0。
而我們期望的是fun()函數(shù)執(zhí)行后能得到三角形的面積,也就是說s引用的對象所執(zhí)行的area操作應(yīng)約束到Triangle類的area()函數(shù)上,這是靜態(tài)聯(lián)編無法實現(xiàn)的。
2.動態(tài)聯(lián)編
動態(tài)聯(lián)編在編譯階段不能決定執(zhí)行哪個同名的被調(diào)函數(shù),只在程序運行過程中根據(jù)需要處理的對象類型來決定執(zhí)行哪個類的成員函數(shù)。
動態(tài)聯(lián)編實際上是進行動態(tài)識別。前面分析靜態(tài)聯(lián)編時,fun()函數(shù)中s的對象被約束到Point類上。我們期望的是,程序運行時能將s的對象約束到Rectangle類上??梢?,同一個對象引用在不同階段被約定的類的對象是不同的。那么如何來確定是靜態(tài)聯(lián)編還是動態(tài)聯(lián)編呢?C++規(guī)定動態(tài)聯(lián)編是在虛函數(shù)支持下實現(xiàn)的。
通過上述分析可以看出,靜態(tài)聯(lián)編和動態(tài)聯(lián)編也是屬于多態(tài)性的,是不同階段對不同實現(xiàn)進行不同的選擇。
3.虛函數(shù)
虛函數(shù)是動態(tài)聯(lián)編的基礎(chǔ)。虛函數(shù)是成員函數(shù)。虛函數(shù)的聲明方法為:
virtual<類型說明符><函數(shù)名>(<參數(shù)表>)
如果某類中的一個成員函數(shù)聲明為虛函數(shù),這意味著該成員函數(shù)在派生類中可能有不同的實現(xiàn)。
【例3-5】
建立一個名為Point的基類,有X、Y坐標屬性,并定義一個虛函數(shù)area()。再定義一個派生類Rectangle,其屬性包括四個角的坐標位置和求面積的成員函數(shù)area(),計算給定四個角坐標的矩形面積。操作步驟如下:
(1)建立一個名為“chap3_5”的“Aemptyproject”。
(2)為例3-5增加一個“C++ResourceFile”,文件名為“chap3_5”。
(3)在工作區(qū)中輸入代碼:
#include"iostream.h"
#include"math.h"
classPoint//點類
{
private:
doublex,y;
public:
Point(inti,intj)
{ x=i;
y=j;
}
virtualdoublearea()
{
return0.0;
}
};
classTriangle:publicPoint//基類為Point類的派生類?-?直角三角形類
{
private:
floatbottom,height;
public:
Triangle(inti,intj,intk,intl,intm,intn);//構(gòu)造函數(shù)輸入直角三角形三點坐標 doublearea()
{
return0.5*bottom*height;
}
};
Triangle::Triangle(inti,intj,intk,intl,intm,intn):Point(i,j)//初始化Point參數(shù)并計算矩形寬、高
{
bottom=m-k;
height=l-j;
}
voidfun(Point&s)
{
cout<<s.area()<<endl;
}
voidmain()
{
Triangletri(10,10,10,50,100,50);//初始化矩形參數(shù)
fun(tri);//調(diào)用函數(shù)fun求面積
}
(4)按“Ctrl+F5”鍵運行程序,執(zhí)行結(jié)果如圖3-11所示。圖3-11給定四個角坐標下矩形面積試比較chap3_5與chap3_4代碼有何不同?可以看到,chap3_5中Point類成員函數(shù)area()前添加了virtual關(guān)鍵字。在此例中,Point中area()函數(shù)被聲明為虛函數(shù)。在程序運行時,s被動態(tài)聯(lián)編,被約束為Triangle類中的area()函數(shù)。通過這個例子可以看到,派生類中對基類的虛函數(shù)進行替換時,要求派生類中說明的虛函數(shù)與基類中的被替換的虛函數(shù)滿足如下條件:
(1)與基類的虛函數(shù)有相同的參數(shù)個數(shù)。
(2)其參數(shù)的類型與基類的虛函數(shù)的對應(yīng)參數(shù)類型相同。
3.5類、繼承與派生、多態(tài)性綜合實例
【例3-6】計算圖形面積。給出4種簡單的幾何圖形,求出其面積。
計算公式:
三角形(Triangle)面積公式:底×高÷2
矩形(Rectangle)面積公式:長×寬
圓(Circle)面積公式:π×半徑×半徑
梯形(Trapeziod)面積公式:(上底+下底)×高÷2
操作步驟如下:
(1)建立一個名為“chap3_6”的“Aemptyproject”。
(2)為例3-6增加一個“C++ResourceFile”,文件名為“chap3_6”。(3)在工作區(qū)中輸入代碼:
#include"iostream.h"
#include"string.h"
classShape//定義基類
{
public:
virtualchar*n()
{
return0;
}
virtualdoublearea()
{
return0.0;
}
};classTriangle:publicShape//三角形類繼承于Shape類
{
private:
doublebottom;
doubleheight;
charname[20];
public:
Triangle(doubleb,doubleh)//構(gòu)造函數(shù)
{
bottom=b;//底
height=h;//高
}
char*n()
{ strcpy(name,"三角形");
returnname;
}
doublearea()//計算面積
{
returnbottom*height*0.5;
}
};
classRectangle:publicShape
//Rectangle類繼承于Shape類
{
private:
doubleheight;
//高
doublewide;
//寬
charname[20];
public: Rectangle(doubleh,doublew)//構(gòu)造函數(shù)
{
height=h;
wide=w;
}
doublearea()//計算面積
{
returnheight*wide;
}
char*n()
{
strcpy(name,“矩形”);
returnname;
}
};classCircle:publicShape//圓形類繼承于Shape類
{
private:
doubleradius;//半徑
charname[20];
public:
Circle(doubler)//構(gòu)造函數(shù)
{
radius=r;
}
doublearea()//計算面積
{
return3.14*radius*radius;
}
char*n()
{
strcpy(name,"圓形");
returnname;
}
};
classTrapeziod:publicShape//梯形類繼承于Shape類
{
溫馨提示
- 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)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 專業(yè)定制塑鋼窗戶采購協(xié)議示例(2024年度)版B版
- 二零二五年度瓷磚行業(yè)環(huán)保設(shè)施建設(shè)合同3篇
- 2025年度教育課程策劃開發(fā)合同范本4篇
- 2025年度智慧社區(qū)場商位租賃及社區(qū)服務(wù)合同4篇
- 2025年度文化旅游區(qū)場地承包經(jīng)營與開發(fā)合同模板3篇
- 2025年度現(xiàn)代化廠房施工建設(shè)合同(新版)4篇
- 2024年貨物買賣合同跨境電商條款
- 2025年度叉車租賃與租賃物租賃期限續(xù)簽合同4篇
- 專屬校車司機招聘協(xié)議:2024年版詳盡協(xié)議版B版
- 2024贊助合同書范本:展覽贊助合作協(xié)議3篇
- 智慧工廠數(shù)字孿生解決方案
- 病機-基本病機 邪正盛衰講解
- 品管圈知識 課件
- 非誠不找小品臺詞
- 2024年3月江蘇省考公務(wù)員面試題(B類)及參考答案
- 患者信息保密法律法規(guī)解讀
- 老年人護理風(fēng)險防控PPT
- 充電樁采購安裝投標方案(技術(shù)方案)
- 醫(yī)院科室考勤表
- 鍍膜員工述職報告
- 春節(jié)期間化工企業(yè)安全生產(chǎn)注意安全生產(chǎn)
評論
0/150
提交評論