《計算思維與C語言概述》-第十二章_第1頁
《計算思維與C語言概述》-第十二章_第2頁
《計算思維與C語言概述》-第十二章_第3頁
《計算思維與C語言概述》-第十二章_第4頁
《計算思維與C語言概述》-第十二章_第5頁
已閱讀5頁,還剩128頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

12.1類的繼承與派生

現(xiàn)代程序設(shè)計的一個重要方法是代碼重用,

利用自己或別人已經(jīng)寫好的代碼來提高程序的生產(chǎn)效率。

面向?qū)ο蟪绦蛟O(shè)計的一個重要特征就是代碼重用。

類的創(chuàng)建將數(shù)據(jù)抽象并封裝為一種新的數(shù)據(jù)類型。將創(chuàng)建好的類加入類庫以供程序員隨時調(diào)用,增強代碼的重用性,提高程序開發(fā)效率。面向?qū)ο蟪绦虻拇a重用不僅僅指復(fù)制已經(jīng)寫好的代碼到自己的程序中,還指利用已經(jīng)創(chuàng)建好的類構(gòu)建出功能更強大的類。這便是類的繼承和派生。繼承(inheritance)就是在一個已存在的類A的基礎(chǔ)上建立一個新類B。

類A稱為基類(baseclass)或父類(fatherclass),

類B稱為派生類(derivedclass)或子類(sonclass)。一個類也可以派生多個類,當然,一個類也可以派生自多個類。下一頁返回12.1類的繼承與派生

多態(tài)(polymorphism)是面向?qū)ο缶幊填I(lǐng)域的核心概念。

在C++中,

多態(tài)性分為兩種:一種稱為編譯時多態(tài),另一種為運行時多態(tài)。編譯時多態(tài),也就是函數(shù)重載,在編譯時系統(tǒng)就能確定調(diào)用不同函數(shù)的多態(tài)性。如果在編譯時不能確定調(diào)用的是哪個函數(shù),而是在程序運行過程中才能確定操作哪個對象,才能確定調(diào)用哪個函數(shù),則將這種多態(tài)稱為運行時多態(tài)。模板是泛型編程(genericprogramming)的基礎(chǔ)。

泛型具有在多種數(shù)據(jù)類型上皆可操作的含義。模板把一個原本特定于某個類型的算法或類當中的類型信息抽出作為模板參數(shù)。函數(shù)模板可以用來批量生成功能和參數(shù)幾乎相同的函數(shù),而類模板用來批量生成功能和形式都幾乎相同的類。上一頁下一頁返回12.1類的繼承與派生

一個新類B從已有的類A中獲取特征,這種現(xiàn)象稱為類的繼承。通過繼承,派生類B可以獲取基類A的特性。反過來說,從基類A產(chǎn)生子類B的現(xiàn)象稱為類的派生。派生類可以派生自多個基類,

這種現(xiàn)象稱為多繼承或多重繼承(multipleinheritance);

否則,

稱為單繼承(singleinheritance)。類的繼承機制除了實現(xiàn)代碼重用外,還可以對事物分類,并以層次結(jié)構(gòu)表示,使對象之間的關(guān)系更加清晰。例如,交通工具類是基類,交通工具類派生汽車類、

飛機類、

輪船類等,汽車類派生轎車類、越野車類、房車類等,飛機類派生民航飛機類、軍用飛機類等,如圖12-1所示。上一頁下一頁返回12.1類的繼承與派生

在軟件開發(fā)過程中,可能需要建立多個類,因此必須分析各個類對象之間的關(guān)系,然后按照層次關(guān)系創(chuàng)建類,逐步完成軟件的開發(fā)。例如,在一種應(yīng)用中需要創(chuàng)建各種二維形狀,如矩形,方形、圓、橢圓等。那么這些二維形狀有一些共同特征,我們將其提取出來,構(gòu)造一個基類,命名為Shape(形狀)類,然后在此基礎(chǔ)上派生Rectangle(矩形)類、Eclipse(橢圓)類。因為正方形是特殊的矩形,圓是特殊的橢圓,所以Square(方形)類可由Rectangle類派生,Circle(圓)類可由Eclipse類派生。各類對象之間的層次結(jié)構(gòu)如圖12-2所示。上一頁下一頁返回12.1類的繼承與派生

【例12-1】定義一個基類Shape,在此基礎(chǔ)上派生出Rectangle類和Circle類,進而派生Square類和Circle類,各類之間的繼承關(guān)系如圖12-2所示。類Rectangle,Circle、Square、Circle需要實現(xiàn)計算面積的功能。【分析】首先,創(chuàng)建基類Shape;然后,創(chuàng)建派生類Rectangle和Circle;最后,創(chuàng)建派生類Square和Circle。上一頁下一頁返回12.1類的繼承與派生

12.1.1

基類的定義從形式來說,任何類都可以是基類。但實際上,基類具有所有派生類的共有特征。例12-1中的Shape類具有其派生類的特征,如矩形Rectangle有長和寬兩個特征,而橢圓Eclipse有長軸和短軸兩個特征。因此,在Shape類中需要定義兩個量,用于表示派生類的共同特征,那么派生類Rectangle和Eclipse就不需要再次定義共同特征部分。上一頁下一頁返回12.1類的繼承與派生

Shape類的代碼如下:上一頁下一頁返回12.1類的繼承與派生

上一頁下一頁返回12.1類的繼承與派生

注意:基類中成員的訪問屬性protected。protected訪問特性介于public訪問和private訪問之間。protected成員不可以被全局函數(shù)或其他類的成員函數(shù)訪問,但能被派生類的成員函數(shù)和友元函數(shù)訪問。所以,在基類中,允許在派生類訪問的成員需要將其訪問特性設(shè)置為protected。上一頁下一頁返回12.1類的繼承與派生

12.1.2

派生類的定義與繼承方式定義派生類時,需要指出它從哪個基類派生,在基類的基礎(chǔ)上增加了什么內(nèi)容。派生類定義格式:class派生類名:繼承方式基類1,繼承方式基類2,,繼承方式基類n{新增的成員聲明}繼承方式規(guī)定了如何訪問從基類繼承的成員,可以是public、private和protected。繼承方式可以省略,默認為private。派生類以public方式繼承基類時,基類的public成員會成為派生類的public成員,基類的protected成員會成為派生類的protected成員,而基類的private成員是不能繼承的。上一頁下一頁返回12.1類的繼承與派生

派生類以protected方式繼承基類時,基類的public成員和protected成員會成為派生類的protected成員,而基類的private成員是不能繼承的。派生類以private方式繼承基類時,基類的public成員和protected成員會成為派生類的private成員,而基類的private成員是不能繼承的。通常,繼承采用的方式是public,使基類的成員在派生類中保持原有的訪問特性。例如,例10-2中的Rectangle類以public方式繼承Shape類時,定義如下:classRectangle:publicShape基類Shape類的private數(shù)據(jù)成員x、y成為Rectangle類的private數(shù)據(jù)成員x、y,Shape類的public成員(構(gòu)造函數(shù)與成員函數(shù))成為Rectangle類的public成員。上一頁下一頁返回12.1類的繼承與派生

12.1.3

派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)派生類必須由自己的構(gòu)造函數(shù)來完成初始化。C++規(guī)定,派生類對象的初始化由基類和派生類共同完成。派生類的構(gòu)造函數(shù)體只負責(zé)初始化新增加的數(shù)據(jù)成員,

而在初始化列表中調(diào)用基類的構(gòu)造函數(shù)初始化基類的數(shù)據(jù)成員。派生類構(gòu)造函數(shù)的一般形式如下:派生類構(gòu)造函數(shù)名(參數(shù)表):基類構(gòu)造函數(shù)名(參數(shù)表){}上一頁下一頁返回12.1類的繼承與派生

例12-1的Rectangle類的構(gòu)造函數(shù)如下:Rectangle(doublel=0,doublew=0):Shape(l,w){area=x?y;}派生類對象的析構(gòu)同樣如此。派生類的析構(gòu)函數(shù)體只負責(zé)新增成員的析構(gòu),基類部分由基類的析構(gòu)函數(shù)析構(gòu)。上一頁下一頁返回12.1類的繼承與派生

12.1.4

重定義基類的成員函數(shù)派生類是基類的擴展,可以是數(shù)據(jù)內(nèi)容的擴展(如增加數(shù)據(jù)成員),也可以是功能的擴展(如增加成員函數(shù)或改變基類的成員函數(shù))。派生類對基類的某個功能進行擴展時,它定義的成員函數(shù)名可能與基類的成員函數(shù)名重復(fù),如果只是函數(shù)名相同而原型不同,

則系統(tǒng)認為派生類有兩個重載函數(shù);如果原型相同,則認為派生類有兩個原型一模一樣的函數(shù)。例如,Shape類中有成員函數(shù)display,定義如下:voiddisplay(){cout<<'('<<x<<','<<y<<')'<<endl;}上一頁下一頁返回12.1類的繼承與派生

如果派生類Rectangle也需要定義一個輸出函數(shù)display,定義如下:voiddisplay(){cout<<'('<<x<<','<<y<<')'<<endl;cout<<"Area:"<<area<<endl;}上述原型相同的成員函數(shù),稱為重定義基類的成員函數(shù)。在這種情況下,派生類對象調(diào)用的是派生類重新定義的成員函數(shù)。

例如,

定義Rectangle的對象r,

那么rdisplay()執(zhí)行的是Rectangle類的display函數(shù)??梢钥闯?,在派生類display函數(shù)的輸出內(nèi)容中,有一部分與基類display輸出函數(shù)內(nèi)容相同。因此,可以調(diào)用基類的display函數(shù)來完成這部分功能。上一頁下一頁返回12.1類的繼承與派生

使用方法是在函數(shù)名前加基類名稱的限定。代碼如下:voiddisplay(){Shape∷display();cout<<"Area:"<<area<<endl;}上一頁下一頁返回12.1類的繼承與派生

12.1.5

派生類的定義例12-1派生類Rectangle的定義代碼如下:上一頁下一頁返回12.1類的繼承與派生

上一頁下一頁返回12.1類的繼承與派生

在定義派生類對象時,編譯系統(tǒng)先執(zhí)行基類Shape的構(gòu)造函數(shù),然后執(zhí)行派生類的構(gòu)造函數(shù)。例如,定義如下Rectangle類對象:Rectangler1,r2(3,4);r1.display();r2.display();對象r2(3,4)先執(zhí)行Shape(3,4),

然后執(zhí)行自己的函數(shù)體。

上述代碼執(zhí)行了Rectangle類的成員函數(shù)display。運行結(jié)果:(0,0)Area:0(3,4)Area:12上一頁下一頁返回12.1類的繼承與派生

派生類對象銷毀時,編譯器自動調(diào)用派生類Rectangle的析構(gòu)函數(shù),然后調(diào)用基類Shape函數(shù)的析構(gòu)函數(shù)。例如,對象r1、r2銷毀時,運行結(jié)果如下:Area:12Rectangle(3,4)iscleaningShape(3,4)iscleaningRectangle(0,0)iscleaningShape(0,0)iscleaning上一頁下一頁返回12.1類的繼承與派生

一個基類可以派生多個派生類。因此,基類Shape還可以派生多個二維圖形類,如表示橢圓的Eclipse類。在派生類Eclipse中,基類成員x和y表示橢圓的長軸和短軸。成員函數(shù)getArea利用長軸和短軸求得橢圓的面積。創(chuàng)建派生類Eclipse類的代碼如下:上一頁下一頁返回12.1類的繼承與派生

上一頁下一頁返回12.1類的繼承與派生

綜上所述,例12-1的派生類Rectangle和Eclipse都繼承了基類Shape的成員,并增加了數(shù)據(jù)成員area,重新定義了成員函數(shù)display,其UML(UnifiedModelingLanguage,統(tǒng)一建模語言)類圖如圖12-3所示。上一頁下一頁返回12.1類的繼承與派生

12.1.6

類的多層派生一個類不僅可以派生多個類,而且派生類也可以作為基類,繼續(xù)派生新類,形成派生的層次結(jié)構(gòu)。圖12-4所示的UML類圖展示了例12-1的多級派生結(jié)構(gòu)??梢钥闯?,下層派生類可以通過繼承關(guān)系引用基類中可以繼承的成員。在例12-1中,Square類由Retangle類派生,Cricle類由Eclipse類派生。對于方形類Square,x和y均表示為方形的邊長并且x與y的值相等,方形面積的計算直接調(diào)用基類Retangle成員函數(shù)getArea即可;對于圓形類Cricle,x和y均表示為圓的半徑且x與y的值相等,圓形面積的計算直接調(diào)用基類Eclipse的成員函數(shù)getArea即可。上一頁下一頁返回12.1類的繼承與派生

創(chuàng)建方形類Square和圓形類Cricle的代碼如下:上一頁下一頁返回12.1類的繼承與派生

上一頁下一頁返回12.1類的繼承與派生

當構(gòu)造派生類對象時,不需要知道基類的對象是如何構(gòu)造的,只需要調(diào)用基類的構(gòu)造函數(shù)即可。例如,Square類的構(gòu)造函數(shù)只需要調(diào)用基類Rectangle的構(gòu)造函數(shù),不需要知道Rectangle的構(gòu)造函數(shù)由Shape類的構(gòu)造函數(shù)構(gòu)造的。語句如下:Square(doublel=0):Rectangle(l,l){}該代碼體現(xiàn)了方形為邊長相同的矩形的概念。Square類和Cricle類對象可以直接使用基類Rectangle與Eclipse成員函數(shù)來計算面積:Circlec1(1);Squares1(1);c1.display();s1.display();上一頁下一頁返回12.1類的繼承與派生

對象c1生成時,首先執(zhí)行Eclipse類的構(gòu)造函數(shù),然后執(zhí)行Circle類的構(gòu)造函數(shù)體。在執(zhí)行Eclipse類的構(gòu)造函數(shù)時,首先執(zhí)行Shape類的構(gòu)造函數(shù),然后執(zhí)行Eclipse類的構(gòu)造函數(shù)。上述代碼執(zhí)行了Circle類與Square類的成員函數(shù)display。運行結(jié)果:(1,1)Area:314159(1,1)Area:1上一頁下一頁返回12.1類的繼承與派生

對象的析構(gòu)過程也是如此。例如,對象s1析構(gòu)時,首先執(zhí)行Square類的析構(gòu)函數(shù),然后執(zhí)行Rectangle類的析構(gòu)函數(shù),最后執(zhí)行Shape類的析構(gòu)函數(shù)。上述代碼的析構(gòu)顯示結(jié)果如下:Square(1,1)iscleaningRectangle(1,1)iscleaningShape(1,1)iscleaningCircle(1,1)iscleaningEclipse(1,1)iscleaningShape(1,1)iscleaning上一頁下一頁返回12.1類的繼承與派生

【練習(xí)】在例12-1的Rectangle類、

Eclipse類中增加計算周長的功能,

實現(xiàn)Rectangle類、

E ̄clipse類、Square類、Circle類都能計算周長和面積,并編寫代碼測試其功能。上一頁返回12.2多重繼承

12.1節(jié)介紹了單繼承,即新類是從一個基類派生而來的。然而,在實際應(yīng)用中,存在多重繼承的情況。例如,班長既是學(xué)生,又是學(xué)生會成員,由兩個類別派生而來;學(xué)校中有學(xué)生和教師兩個群體,但有些教師同時在攻讀碩士研究生或博士研究生,其身份既是教師,又是學(xué)生。本節(jié)以具體示例來說明多重繼承的構(gòu)造。下一頁返回12.2多重繼承

【例12-2】定義大學(xué)中的部分群體———教師(Teacher)類和學(xué)生(Student)類,

同時構(gòu)造在職研究生(JGraduate)類。

在定義類對象時,

給出初始化數(shù)據(jù),

然后輸出這些信息?!痉治觥繛榱苏f明方便,在此采用較少屬性來表示上述群體特征。教師類的屬性包括:教師編號(tNo)、

身份證號碼(ID)、

姓名(name)、

性別(sex)、

年齡(age)、

職稱(title)。

學(xué)生類的屬性包括:學(xué)號(sNo)、

身份證號碼(ID)、

姓名(name)、

性別(sex)、年齡(age)、

攻讀學(xué)位(degree)。

在職研究生同時具有學(xué)生和教師兩個類別的屬性。

每個類的構(gòu)造函數(shù)實現(xiàn)數(shù)據(jù)的初始化,成員函數(shù)display實現(xiàn)數(shù)據(jù)的輸出。上一頁下一頁返回12.2多重繼承

由三個類的屬性可以看出,學(xué)生屬性和教師屬性有大部分信息是重復(fù)的。面向?qū)ο笏季S的一個重要思想是代碼重用,所以提取二者的共同屬性來構(gòu)造一個基類,將與之不同的屬性放入派生類中,在派生類對象的使用中實現(xiàn)代碼重用。在本例中,學(xué)生類和教師類的共同屬性有身份證號碼(ID)、

姓名(name)、

性別(sex)、

年齡(age)等。

在此,

將共同屬性提取作為基類Citizen的數(shù)據(jù)成員,體現(xiàn)學(xué)生和教師都是公民的概念。然后,將教師編號(tNo)、

職稱(Title)作為教師的特有屬性,

而將學(xué)號(sNo)、

攻讀學(xué)位(degree)作為學(xué)生的特有屬性。上述多個類的UML繼承關(guān)系如圖12-5所示。上一頁下一頁返回12.2多重繼承

基類Citizen類的代碼如下:上一頁下一頁返回12.2多重繼承

上一頁下一頁返回12.2多重繼承

上一頁下一頁返回12.2多重繼承

Citizen類派生了Teacher類和Student類,此為單繼承,但Teacher類和Student類作為基類共同派生了JGraduate類,此為多繼承。Teacher類在基類Teacher的基礎(chǔ)上增加了兩個數(shù)據(jù)成員,其中tNo表示教師編號,title表示職稱。Teacher類重定義了display成員函數(shù)顯示教師信息。上一頁下一頁返回12.2多重繼承

Teahcer類的定義代碼如下:上一頁下一頁返回12.2多重繼承

上一頁下一頁返回12.2多重繼承

Student類在基類Teacher基礎(chǔ)上也增加了兩個數(shù)據(jù)成員,

其中sNo表示學(xué)生學(xué)號,degree表示攻讀學(xué)位。Student類也重定義了display成員函數(shù)顯示學(xué)生信息。Student類的定義代碼如下:上一頁下一頁返回12.2多重繼承

上一頁下一頁返回12.2多重繼承

12.2.1

多重繼承的聲明如果已聲明了類A、類B和類C,則可聲明多重繼承的派生類D。例12-2的JGraduate類由Teacher類和Student類共用派生,其聲明方式及代碼如下:上一頁下一頁返回12.2多重繼承

上一頁下一頁返回12.2多重繼承

多重繼承派生類的構(gòu)造函數(shù)形式與單繼承時的構(gòu)造形式基本相同,

只是在初始化表中包含了多個基類構(gòu)造函數(shù)。例如,JGraduate類的初始化表中既包含了Teacher的初始化,也包含了Student的初始化(注意此時參數(shù)的設(shè)置)。執(zhí)行順序:首先,執(zhí)行Teacher的構(gòu)造函數(shù);然后,執(zhí)行Student的構(gòu)造函數(shù);最后,執(zhí)行自己的構(gòu)造函數(shù)。由JGraduate類的定義代碼可知,JGraduate類重新定義了成員函數(shù)display,并且調(diào)用了兩個基類的同名成員函數(shù)display。調(diào)用方式:基類名:成員函數(shù)名代碼Teacher∷display()或Student∷display()執(zhí)行了基類的成員函數(shù)。綜上所述,在例12-2中,通過繼承三個繼承類的類成員如圖12-6所示。從中可以看出,

多重繼承類的成員含有雙份的姓名(name)、

性別(sex)、

年齡(age)信息。上一頁下一頁返回12.2多重繼承

12.2.2

多重繼承派生類對象的定義多重繼承派生類對象的定義方式與單繼承的方式相同。下面的代碼定義了JGraduate類對象并調(diào)用了display函數(shù):JGradutejg("20001234","Lecturer","2002123345","Doctor","370823197801234567","Tom","male",24);jgdisplay();在上面代碼中,JGraduated類對象jg調(diào)用JGraduated類的display函數(shù),而不是基類Teacher或Student的display函數(shù)。上一頁下一頁返回12.2多重繼承

如果對象jg調(diào)用Teacher類或Student類的display函數(shù)(可查看12-5所示的繼承關(guān)系),可以采用如下方式:jgTeacher∷display();jgStudent∷display();但是,對象jg調(diào)用Citizen類的display容易產(chǎn)生二義性。觀察圖12-5所示的繼承關(guān)系,編譯系統(tǒng)此時不能分清是從左邊的繼承關(guān)系取得Citizen類的display,還是從右邊的繼承關(guān)系取得Citizen類的display。因此,這種調(diào)用產(chǎn)生了二義性,編譯系統(tǒng)報錯,如下列代碼所示:jgCitizen∷display(); //出錯,系統(tǒng)提示出現(xiàn)歧義上一頁下一頁返回12.2多重繼承

JGraduated類多重繼承了Teacher類和Student類,以及JGraduated類對象jg的析構(gòu)順序:(1)執(zhí)行JGraduated類的析構(gòu)函數(shù)。(2)執(zhí)行Student類的析構(gòu)函數(shù),

而Student類繼承了Citizen類,

因此還需要執(zhí)行Citizen類的析構(gòu)函數(shù)。(3)執(zhí)行Teacher類的析構(gòu)函數(shù),

而Teacher類繼承了Citizen類,

因此還需要執(zhí)行Citizen類的析構(gòu)函數(shù)。上一頁下一頁返回12.2多重繼承

在例12-3中,jg對象銷毀時的運行結(jié)果如下:JGradutedestructor!Studentdestructor!Citizendestructor!Teacherdestructor!Citizendestructor!Citizendestructor!上一頁下一頁返回12.2多重繼承

12.2.3

虛基類由圖12-6可知,多重繼承發(fā)生時,可能將上層基類的成員繼承多份,如JGraduate類就繼承了雙份的姓名(name)、

性別(sex)、

年齡(age)信息,

繼承了雙份的display函數(shù)。C++提供了虛基類(virtualbaseclass)的聲明方法,

使繼承間接共同基類時,

只保留一份成員。虛基類的聲明是指在聲明派生類的繼承方式時聲明。聲明虛基類的一般形式:class派生類名:virtual繼承方式基類名虛基類聲明了一種繼承方式。為了保證基類在派生類只被繼承一份,應(yīng)該在該基類的所有直接派生類中聲明為虛基類。在例12-2中,為了保證將基類Citizen的成員只繼承一份,就需要在類Teacher和類Student派生時都指定Citizen為虛基類。上一頁下一頁返回12.2多重繼承

聲明方式更改如下:classTeacher:virtualpublicCitizenclassStudent:virtualpublicCitizen改變了聲明方式后,例12-2的JGraduate類成員如圖12-7所示,name、sex、age信息繼承于Citizen類,并且只保留一份,display函數(shù)也繼承于Citizen類,并且只保留一份。如果在虛基類中定義了帶參數(shù)的構(gòu)造函數(shù),而且沒有定義默認構(gòu)造函數(shù),則其所有派生類(包括直接派生或間接派生的派生類)需要通過構(gòu)造函數(shù)的初始化表對虛基類進行初始化。上一頁下一頁返回12.2多重繼承

例如,在【例12-2】中,直接派生類Teacher和類Student都需要使用初始化表進行初始化,間接派生類JGraduate也需要使用初始化表進行初始化。C++規(guī)定,在最后的派生類中不僅要負責(zé)對其直接基類進行初始化,還要負責(zé)對虛基類初始化。因此,派生類JGraduate不僅需要對類Teacher和類Student初始化,還需要對虛基類Citizen初始化。因此,將JGraduate類的構(gòu)造函數(shù)更改如下:上一頁下一頁返回12.2多重繼承

JGraduate類的成員函數(shù)也可以引用虛基類Citizen的成員。成員函數(shù)display可更改如下:上一頁下一頁返回12.2多重繼承

使用了虛基類后,JGraduate類對象可以引用虛基類Citizen的公有成員。例如:JGradutejg("20001234","Lecturer","2002123345","Doctor","370823197801234567","Tom","male",24);jgCitizen∷display();上一頁返回12.3多態(tài)性與虛函數(shù)

多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O(shè)計的一個重要特征。

多態(tài)性有兩種實現(xiàn)方式:編譯時的多態(tài)性(靜態(tài)多態(tài)性、靜態(tài)綁定)和運行時的多態(tài)性(動態(tài)多態(tài)性、動態(tài)綁定)。前面章節(jié)介紹的函數(shù)重載和運算符重載都是靜態(tài)綁定。例如,表達式中加法運算在不同的代碼中調(diào)用的函數(shù)是不同的,這種多態(tài)性在編譯時就能確定。例如,對于int型變量i1、i2執(zhí)行表達式“i1+i2”的加法運算,編譯系統(tǒng)會調(diào)用int型的operate+函數(shù)(系統(tǒng)定義)。但是,對于第11章的Fraction類對象執(zhí)行的加法運算,編譯系統(tǒng)會調(diào)用Fraction類重載的operate+函數(shù)(用戶自定義)。例如,下面的代碼Fraction類對象f1和f2執(zhí)行表達式“f1+f2”,編譯系統(tǒng)會調(diào)用Fraction類的運算符重載函數(shù)。下一頁返回12.3多態(tài)性與虛函數(shù)

Fractionf1(3,6),f2(4,8),f3;f3=f1+f2;這種在編譯時系統(tǒng)就能確定調(diào)用不同函數(shù)的多態(tài)性,稱為編譯時的多態(tài)性,或稱為靜態(tài)多態(tài)性,也稱為靜態(tài)綁定。如果在編譯時不能確定調(diào)用的是哪個函數(shù),

而是在程序運行過程中才能確定操作哪個對象,才能確定調(diào)用哪個函數(shù),則這種多態(tài)性稱為運行時的多態(tài)性,或稱為動態(tài)多態(tài)性,

也稱為動態(tài)綁定。運行時的多態(tài)性通過虛函數(shù)和基類指針指向不同的派生類對象來實現(xiàn)。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

12.3.1

派生類對象向基類對象的轉(zhuǎn)換如果采用public的繼承方式,那么派生類可以完整地繼承基類的功能。例如,例12-1的Rectangle類能夠完整繼承Shape類的功能。定義一個Rectangle類對象r(3,4),那么,對象r的示意如圖12-8所示,對象r中包含了一個基類Shape對象。由前面章節(jié)內(nèi)容可知,要將B類對象自動轉(zhuǎn)換成A類對象,則需要在B類中定義一個向A類轉(zhuǎn)換的類型轉(zhuǎn)換函數(shù)。如果B類是A類的派生類,B對象中包含了一個基類A的對象,則不必定義類型轉(zhuǎn)換函數(shù)。C++規(guī)定,派生類對象可以自動轉(zhuǎn)換成基類對象。例如,一個Rectangle對象r能夠自動轉(zhuǎn)換成一個Shape類對象。那么在什么情況下,系統(tǒng)會執(zhí)行自動執(zhí)行這種轉(zhuǎn)換呢?上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

1.將派生類對象賦值給一個基類的對象由于派生類中包含了一個基類對象,當將一個派生類對象賦給一個基類對象時,或者一個基類對象使用一個派生類對象賦值時,就是將派生類中的基類部分賦給此基類對象。例如:Rectangler(3,4);Shapes=r;上述代碼中的賦值操作舍棄了派生類對象r中自己的成員,將r中的基類部分賦給了s,如圖12-9所示。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

2.基類指針指向派生類對象讓一個基類指針指向派生類對象,如:Rectangler(3,4);Shape?sp=&r;sp->display();//引用的是Shape類的成員函數(shù)盡管該指針sp指向的對象是一個派生類對象r,但由于本身是一個基類Shape指針,因此只能解釋基類的成員而不能解釋派生類新增的部分。sp只引用對象r的Shape部分,sp->display也只執(zhí)行了Shape類的display函數(shù)。上述代碼的運行結(jié)果:(3,4)如果試圖通過基類指針引用派生類的新增成員時,則編譯系統(tǒng)報錯:cout<<sp->area; //報錯上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

3.基類對象引用派生類對象引用,實質(zhì)上是一種隱式的指針。當用一個基類對象引用派生類對象時,相當于給派生類中的基類部分取了一個名字,基類對象只看到了派生類中的基類部分。例如:Rectangler(3,4);Shape&r1=r; //基類對象引用派生類對象r1display(); //引用的是Shape類的成員函數(shù)r1是r的一個別名,但它的類型是Shape類型,所以r1只能引用r中的基類部分。r1display()引用的是Shape類的成員函數(shù)。

如果試圖通過基類指針引用派生類的新增成員時,則編譯系統(tǒng)報錯:cout<<r1area; //報錯上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

12.3.2

虛函數(shù)由12.3.1節(jié)可知,基類的指針或引用可以指向派生類的對象,但只能訪問派生類對象中的基類部分,不能訪問派生類的新增成員。C++提供了虛函數(shù)來解決這個問題。虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù)。例12-1的基類Shape、派生類Rectangle、派生類Eclipse的成員函數(shù)都可以定義為虛函數(shù),通過基類指針或引用來訪問基類虛函數(shù),可以達到訪問派生類虛函數(shù)的目的。定義虛函數(shù)時,只需在類的成員函數(shù)前加一個關(guān)鍵字virtual。在派生類中重新定義時,它的函數(shù)原型必須與基類中的虛函數(shù)完全相同,否則編譯系統(tǒng)會認為派生類有兩個重載函數(shù)。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

例如,將例12-1中Shape類的析構(gòu)函數(shù)和display函數(shù)定義為虛函數(shù),增加成員函數(shù)getArea作為虛函數(shù)。代碼如下:上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

派生類虛函數(shù)定義時,函數(shù)原型前面的關(guān)鍵字virtual可以寫,也可以省略。無論函數(shù)原型前面有沒有關(guān)鍵字virtual,重寫的派生類函數(shù)都將自動成為虛函數(shù)。例如,display函數(shù)和getArea函數(shù)在基類是虛函數(shù),那么在派生類中也是虛函數(shù)。在派生類Rectangle中重寫的getArea函數(shù)和display函數(shù)的代碼如下:上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

如下定義基類和派生類的對象(或指針),并執(zhí)行相關(guān)代碼:上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

在上面代碼中,基類對象s1被派生類對象r賦值后,將r中的基類部分賦給了s1。那么,

s1的數(shù)據(jù)成員值變成了3、

4。

s1display()調(diào)用的是基類的成員函數(shù)。

虛函數(shù)對賦值對象的成員函數(shù)調(diào)用不起作用?;愔羔槪螅穑敝赶虻氖桥缮悓ο螅?。由于在基類中display是虛函數(shù),因此當通過基類指針找到基類中的這個函數(shù)時,它也會到派生類中去檢測是否被重新定義。如果在Rectangle中重新定義了這個函數(shù),則執(zhí)行的是派生類中的display函數(shù)?;愐茫螅穑彩桥缮悓ο螅虻膭e名,但其引用類型為基類類型。在系統(tǒng)執(zhí)行sp2display()時,

也會先在基類中查找display()函數(shù)。

若發(fā)現(xiàn)此函數(shù)為虛函數(shù),

系統(tǒng)則會在派生類中檢測該函數(shù)是否被重新定義。若該函數(shù)被重新定義,則執(zhí)行派生類的display函數(shù)。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

在類的多重繼承與多層派生中,如果派生類的對象是通過基類的指針操作的,則基類和派生類的析構(gòu)函數(shù)最好是虛函數(shù)。

如果將基類的析構(gòu)函數(shù)聲明為虛函數(shù),

那么派生類中的析構(gòu)函數(shù)自動成為虛函數(shù)。如果將析構(gòu)函數(shù)定義為虛函數(shù),那么當基類指針銷毀時,基類和派生類的析構(gòu)函數(shù)都被執(zhí)行,這樣就能把派生類對象完全析構(gòu),而不是只析構(gòu)派生類中的基類部分。換言之,定義為虛函數(shù)的析構(gòu)函數(shù)能夠使對象析構(gòu)得更加徹底。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

例如,執(zhí)行代碼:Shape?sp=newRectangle(5,6);sp->display();deletesp;執(zhí)行結(jié)果如下:(5,6)Area:30Rectangle(5,6)iscleaningShape(5,6)iscleaning可以看出,執(zhí)行語句“deletesp”時,編譯系統(tǒng)調(diào)用了基類Shape的析構(gòu)函數(shù)和派生類Rectangle的析構(gòu)函數(shù),

從而使語句newRectangle(5,6)”

申請的派生類對象被徹底析構(gòu)。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

12.3.3

純虛函數(shù)在面向?qū)ο蟪绦蛟O(shè)計中,我們將分析實際問題中有多少對象,需要定義多少類,并提取所有類的共同信息,構(gòu)造一個基類,將與之不同的信息放入派生類中。例如,在例12-1中,將二維圖形橢圓和矩形的共同特征提取出來,將其定義為Shape類,但Shape類對象不是二維圖形,不具備面積、周長等特征。然而,利用Shape類,可以實現(xiàn)代碼重用,實現(xiàn)多態(tài)性等特性。在C++中,可以在這種基類中聲明一種純虛函數(shù),即不需要在基類中定義,而在派生類中定義的一種虛函數(shù)。純虛函數(shù)的聲明形式:virtual返回類型函數(shù)名(參數(shù)表)=0;上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

例如,將例12-1中Shape類的成員函數(shù)getArea聲明為純虛函數(shù):virtualdoublegetArea()const=0;注意:純虛函數(shù)是未定義完全的函數(shù)。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

12.3.4

抽象類如果一個類含有純虛函數(shù),則被稱為抽象類。例如,在例12-1的Shape類中定義多個純虛函數(shù),使其成為一個抽象類。代碼如下:上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

因為抽象類中有未定義完全的函數(shù),所以無法定義抽象類的對象。如果試圖定義抽象類對象,則編譯系統(tǒng)報錯。例如:Shapes(1,2); //出錯但可以定義指向抽象類的指針,其作用是指向派生類對象,實現(xiàn)運行時的多態(tài)性。例如:Shape?sp=newRectangle(5,6);cout<<sp->getArea()<<endl;如果一個抽象類的派生類重新定義了抽象類中的所有純虛函數(shù),

那么這些函數(shù)就不再是純虛函數(shù),這個派生類也不再是抽象類,而是一個可以定義對象的具體類。例如,如果Rectangle類重新定義了基類Shape的所有純虛函數(shù),

那么Rectangle

就不再是一個抽象類;反之,該類仍是一個抽象類。上一頁下一頁返回12.3多態(tài)性與虛函數(shù)

抽象類往往用來表征對問題領(lǐng)域進行分析、

設(shè)計得出的抽象概念,

是對一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象。

抽象類的作用是保證派生類都具有抽象類的純虛函數(shù)所要求的行為,避免繼承類的定義漏掉某種功能的實現(xiàn)。上一頁返回12.4類模板和泛型編程

與函數(shù)模板的作用類似,類模板用來批量生成功能和形式都幾乎相同的類。在面向?qū)ο蟪绦蛟O(shè)計中,允許將類中成員的類型設(shè)為可變的參數(shù),使多個類變成一個類,這樣定義的類稱為類模板。

模板是泛型編程(GenericProgramming)的基礎(chǔ)。

泛型具有在多種數(shù)據(jù)類型上皆可操作的含義,泛型編程用于編寫完全一般化并可重復(fù)使用的算法,適用于數(shù)據(jù)結(jié)構(gòu)與算法設(shè)計。下一頁返回12.4類模板和泛型編程

【例12-3】定義一個泛型的動態(tài)數(shù)組類,該數(shù)組能夠存取各種類型的數(shù)據(jù)?!痉治觥克^動態(tài),就是定義數(shù)組的規(guī)??梢允亲兞炕蛘吣硞€表達式的執(zhí)行結(jié)果。如果不使用類模板,那么存儲int型的動態(tài)數(shù)組就需要定義一個int型動態(tài)數(shù)組類,存儲double型的動態(tài)數(shù)組就需要定義一個double型的動態(tài)數(shù)組類定義一個類模板就可以解決這個問題。將數(shù)組元素的類型設(shè)定為一個可變的參數(shù),稱為模板形式參數(shù),簡稱模板形參。當需要int型的動態(tài)數(shù)組時,就設(shè)置模板形參為int型;當需要double型的動態(tài)數(shù)組時,就設(shè)置模板形參為double型。上一頁下一頁返回12.4類模板和泛型編程

12.4.1

類模板的定義對于功能相同而數(shù)據(jù)類型不同的類,不必定義所有類,只要定義一個可對任何類進行操作的類模板即可。類模板是一種參數(shù)化類型,

絕大多數(shù)模板的形式參數(shù)是表示類型的類型參數(shù)。將類中不確定的類型設(shè)計成一個模板參數(shù),用模板參數(shù)代替類中的某些成員的類型,這樣的類模板的定義格式如下:template<類型形參表>class類模板名{ };類模板的定義以關(guān)鍵字template開頭,后接模板的類型形參表。如果有多個形參,則在兩個參數(shù)之間用逗號分隔,每個類型的形參用關(guān)鍵字class或typename開頭,后接形參名。上一頁下一頁返回12.4類模板和泛型編程

例12-3中的類模板可定義為如下形式:template<classT>classiList{}其中,類模板名為iList,該類模板有一個模板參數(shù)T,表示數(shù)組元素的類型。同類的定義相似,類模板中包含了數(shù)據(jù)成員和成員函數(shù)。我們將例12-3的類模板的數(shù)據(jù)成員設(shè)為兩個:一個是指針變量data,

表示表中存放數(shù)據(jù)的內(nèi)存首地址,

數(shù)據(jù)類型為T?;另一個是int型變量length,表示數(shù)組中存儲數(shù)據(jù)的個數(shù)。類模板中的成員函數(shù)既可以定義在類內(nèi),也可以定義在類外。上一頁下一頁返回12.4類模板和泛型編程

例如,為例12-3定義下列的成員函數(shù):(1)iList():無參構(gòu)造函數(shù)。(2)iList(T[],int):有參構(gòu)造函數(shù),

建立一個長度為n的表,

并用一個數(shù)組初始化數(shù)據(jù)。(3)iList(constiList&):復(fù)制構(gòu)造函數(shù),

使用另一個動態(tài)數(shù)組初始化。(4)iList<T>&operator=(constiList<T>&):重載賦值運算符。(5)~iList():析構(gòu)函數(shù)。(6)intLength():求數(shù)組長度。(7)T&operator[](int):重載下標運算符。上一頁下一頁返回12.4類模板和泛型編程

類模板的大部分成員函數(shù)都是類模板參數(shù)的函數(shù)模板。例12-3的成員函數(shù)需要用到數(shù)組元素類型時,都需要使用模板參數(shù)T代替。對于代碼較少的成員函數(shù),可以將其定義在類內(nèi)。例如,將例12-3的類模板定義在頭文件iList.h中。代碼如下:上一頁下一頁返回12.4類模板和泛型編程

上一頁下一頁返回12.4類模板和泛型編程

在類模板外定義的成員函數(shù)具有如下形式:template<模板形參表>返回類型類模板名<模板形參表>∷函數(shù)名(形參表){ }上一頁下一頁返回12.4類模板和泛型編程

例如,將例12-3類模板的實現(xiàn)部分存入文件iList.cpp。代碼如下:上一頁下一頁返回12.4類模板和泛型編程

上一頁下一頁返回12.4類模板和泛型編程

上一頁下一頁返回12.4類模板和泛型編程

12.4.2

類模板的實例化模板只是一個藍圖,無法在計算機上直接運行。要運行類模板,必須指定模板形參的值,使模板成為一個真正可以運行的程序。

從模板生成一個特定的類或函數(shù)的過程稱為模板的實例化。函數(shù)模板的實例化是由編譯器自動完成的。編譯器在編譯到調(diào)用函數(shù)模板的語句時,會根據(jù)實參的類型來判斷該如何替換模板中的類型參數(shù)。例如,927節(jié)的函數(shù)調(diào)用語句swap(2,3)在執(zhí)行時,編譯器會自動判斷參數(shù)為int型,將函數(shù)模板的形參替換為int型,自動生成voidSwap(int&,int&)函數(shù)。上一頁下一頁返回12.4類模板和泛型編程

類模板的實例化不能由編譯器自動完成。如果定義了例12-3中類模板iList的對象list,編譯器不能確定類模板iList的模板參數(shù)T是什么類型。類模板對象定義時,需要用戶明確指出模板形參的值。格式如下:類模板名<模板的實際參數(shù)表>對象名表編譯系統(tǒng)執(zhí)行類模板對象定義語句時,

將模板的實際參數(shù)表替換模板定義的模板形參表,生成真正可以運行的類。下面的代碼定義了例12-3的iList類模板對象:inta[6]={1,2,3,4,5,6};iList<int>list1(a,6),list2;iList<double>list3;上一頁下一頁返回12.4類模板和泛型編程

上面代碼的語句“iList<int>list1(a,6)”

定義了一個類模板對象,

模板的實際參數(shù)是編int。譯該語句時,編譯系統(tǒng)會將模板iList定義中所有的模板形參T替換為int,生成一個數(shù)組元素類型為int的類。同樣,編譯語句“iList<double>list3”時,編譯系統(tǒng)會將模板iList定義中的所有模板形參T替換為double,生成一個數(shù)組元素類型為double的類。類模板對象的使用與普通的對象完全相同。例如,定義了對象list1和list2后,可以使用下列代碼將list2對象使用list1賦值,并輸出下標3處的元素值。list2=list1;cout<<list1[3];注意:有些編譯器要求在測試文件中必須包含類模板的實現(xiàn)文件。例如:#include"iList.cpp"上一頁下一頁返回12.4類模板和泛型編程

12.4.3

類模板的友元類模板可以聲明友元類或友元函數(shù)。類模板可以聲明以下兩種友元:(1)普通友元:聲明普通的類(或全局函數(shù))為所定義的類模板的友元。(2)模板實例的友元:聲明某個類模板(或函數(shù)模板)的實例為所定義的類模板的友元。如果將一個普通類(或全局函數(shù))聲明為所定義類的友元,那么其格式與定義類的友元相同。一般形式如下:template<模板形參表>classA{friendclassB;friendvoidf();?};上一頁下一頁返回12.4類模板和泛型編程

在上述代碼中,類模板A中聲明了類B和全局函數(shù)f為類A的友元,類B和全局函數(shù)f可以訪問類模板A的所有實例的成員。如果將一個類模板B或函數(shù)模板f的實例聲明為類模板A的友元,

那么需要設(shè)置類模板B或函數(shù)模板f的模板參數(shù)。

類模板B或函數(shù)模板f的模板參數(shù)與類模板A的模板參數(shù)既可以相同,也可以不同。上一頁下一頁返回12.4類模板和泛型編程

【例12-4】為例12-3中的類模板iList增加輸出運算符重載函數(shù),可以直接輸出所有數(shù)據(jù)?!痉治觥堪搭}目要求,如果已用下列代碼定義了iList類的實例(或?qū)ο?:inta[6]={1,2,3,4,5,6};iList<int>list1(a,6);要想可以執(zhí)行“cout<<list1”,

那么需要為iList類模板增加一個友元函數(shù)———輸出運算符重載函數(shù)。上一頁下一頁返回12.4類模板和泛型編程

可以看出,在上面代碼中,運算cout<<list1的第1個運算對象是cout,類型為ostream&;第2個運算對象是list1,類型為iList<int>。iList<int>為類模板iList的具體實例。那么,定義運算符重載函數(shù)時,不能直接使用iList<int>,可以使用模板參數(shù)表示。形式如下:ostream&operator<<(ostream&,constiList<T>&);上一頁下一頁返回12.4類模板和泛型編程

上述運算符重載函數(shù)是函數(shù)模板,包含了模板參數(shù)。值得注意的是,函數(shù)模板的參數(shù)與類模板參數(shù)相同。當聲明該函數(shù)為友元函數(shù)時,必須先聲明該函數(shù)模板及類模板的存在。例如,例12-4聲明友元函數(shù)的類模板首先需要聲明類模板與函數(shù)模板的存在,然后定義類模板并在類模板中聲明友元函數(shù)。代碼如下:上一頁下一頁返回12.4類模板和泛型編程

在上述代碼中,函數(shù)模板參數(shù)與類模板的參數(shù)相同。也就是說,函數(shù)模板只能訪問與其相同模板參數(shù)的類模板特定實例。

注意:需要前置聲明類模板和函數(shù)模板;友元函數(shù)的函數(shù)名后面需要添加<>。如果希望函數(shù)模板能訪問iList類的所有實例的成員,那么不需要前置聲明類模板和函數(shù)模板,直接在類iList中聲明為友元函數(shù)即可。代碼如下:template<classU>friendostream&operator<<(ostream&,constiList<U>&);函數(shù)模板參數(shù)與類模板的模板參數(shù)不同。iList類模板中的模板參數(shù)是T,友元函數(shù)模板的參數(shù)為U,二者不同。上一頁下一頁返回12.4類模板和泛型編程

類模板的友元函數(shù)定義與類模板的成員函數(shù)定義基本相同,不同之處在于,友元函數(shù)不需要加類限定符。template<classU>ostream&operator<<(ostream&os,constiList<U>&list){for(inti=0;i<list.length;i++)os<<listdata[i]<<endl;returnos;}聲明某個類模板實例的友元與聲明某個函數(shù)模板實例的友元類似,在此不再贅述。上一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

實訓(xùn)1

泛化的鏈表類設(shè)計一個泛化的鏈表類,能夠存取各種類型的數(shù)據(jù)。每個節(jié)點包含兩個域:data和next。data域存儲各種類型的數(shù)據(jù),next域為指向節(jié)點的指針。下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

1實訓(xùn)分析題目要求設(shè)計一個泛化的鏈表類,類名為LinkList。在114節(jié)的實訓(xùn)4介紹過,鏈表的第一個節(jié)點不存儲任何數(shù)據(jù)。只需記住指向第一個節(jié)點的指針first,即可存取整個鏈表。類Poly的數(shù)據(jù)成員為first,需要實現(xiàn)的成員函數(shù)如下:(1)LinkList():無參構(gòu)造函數(shù),

建立只有頭節(jié)點的空鏈表。(2)LinkList(DataTypea[],intn):有參構(gòu)造函數(shù),

建立有n個元素的單鏈表。(3)~LinkList():析構(gòu)函數(shù)。(4)ostream&operator<<(ostream&,const

LinkList<U>&):重載輸出運算符,

輸出元素。上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

LinkList類的頭文件LinkList.h的代碼如下:上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

LinkList類的實現(xiàn)文件LinkList.cpp的代碼如下:上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

2實訓(xùn)練習(xí)編寫類LinkList的測試代碼。上一頁下一頁返回12.5實訓(xùn)與實訓(xùn)指導(dǎo)

實訓(xùn)2

圖書館系統(tǒng)中的讀

溫馨提示

  • 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)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論