第2章 面向對象程序設計基礎_第1頁
第2章 面向對象程序設計基礎_第2頁
第2章 面向對象程序設計基礎_第3頁
第2章 面向對象程序設計基礎_第4頁
第2章 面向對象程序設計基礎_第5頁
已閱讀5頁,還剩70頁未讀 繼續免費閱讀

下載本文檔

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

文檔簡介

VisualC++實用教程第2章面向對象程序設計基礎1教學目標:了解面向對象的基本概念

熟練掌握類、對象、派生類的定義和使用

掌握類的構造函數和析構函數的定義和特點

能夠利用虛函數實現多態性熟悉友元的特性

2教學內容:2.1面向對象的基本概念2.2類和對象的定義2.3繼承性和派生類2.4多態性2.5友元2.6模板32.1

面向對象的基本概念觀點:自然界是由實體(對象)所組成。程序設計方法:使用面向對象的觀點來描述、模仿并處理現實問題。要求:高度概括、分類、和抽象。目的:實現軟件設計的產業化。程序=多個對象+消息4類和對象對象是現實世界中一個實際存在的事物對象的靜態特征對象的行為類是具有相同屬性和行為的一組對象的集合,它為屬于該類的全部對象提供了統一的抽象描述,其內部包括屬性和行為兩個主要部分。對象之間的交互:發送消息5封裝封裝的目的是隱藏對象的內部的實現細節。通過封裝,可以將對象的外部接口與內部的實現細節分開。

目的是增強安全性和簡化編程,使用者不必了解具體的實現細節,而只需要通過外部接口,以特定的訪問權限,來使用類的成員。6繼承繼承是C++中支持層次分類的一種機制,允許程序員在保持原有類特性的基礎上,對新類進行更具體的說明。實現:聲明派生類——2.37多態性多態:同一名稱,不同的功能實現方式。目的:標識統一,減少程序中標識符的個數;接口統一,增加程序的靈活性實現:——2.4編譯時的多態性:重載函數運行時的多態性:虛函數82.2類與對象的定義類是C++的靈魂,如果不真正掌握類,就不能真正掌握C++C++中的類就是一種用戶自己定義的數據類型,和其它數據類型不同的是,組成這種類型的不僅可以有數據,而且可以有對數據進行操作的函數。為了封裝的需要,一般將類的定義放在一個.h文件中,而將類的成員函數的實現放在一個.cpp文件中。92.2.1類的定義class類名稱{

public:

公有成員(外部接口)

private:

私有成員

protected:

保護成員};類與外部的接口只允許本類中的函數訪問(可省略)只能由本類及其派生類的成員函數訪問是必需的成員訪問說明符10例2.1:圓類的定義見教材24頁11類的數據成員(成員變量):與一般的變量聲明相同,但需要將它放在類的聲明體中,一般為私有訪問屬性。類的成員函數定義:在類中說明原型,類外給出函數體實現,函數名之前必須加類名和作用域區分符限定將成員函數定義為內聯函數:成員函數在類的內部定義,此時無須使用inline關鍵字,成員函數自動為內聯函數。成員函數在類內聲明,在類外定義。但在類外定義時,要加關鍵字inline。定義與聲明放在同一.h文件中。說明:12const成員函數const成員函數:不修改數據成員的值,在程序中如果不小心修改了這個成員函數中的對象,則編譯器會產生一個語法錯誤信息。const成員函數的定義方法:在函數的原型和定義中,在函數參數表和函數定義的左花括號之間加入const關鍵字。類的成員函數允許重載,允許帶缺省參數值。132.2.2構造函數性質:與類同名、無返回類型在對象創建時由系統自動調用允許重載、帶缺省值如果類中未聲明,則系統自動生成一個缺省形式的構造函數,形如:類名(){}作用:對象的初始化14構造函數舉例---CCircle類classCCircle{public:

CCircle()//無參(缺省)構造函數

{ radius=1;}CCircle(doubler)//帶參構造函數

……private: doubleradius;};CCircle::CCircle(doubler){radius=r>0?r:1;}兩個構造函數合成一個帶缺省值的構造函數CCircle(doubler=1);//構造函數原型CCircle::CCircle(doubler)//構造函數定義{radius=r>0?r:1; }15拷貝構造函數拷貝構造函數是一種特殊的構造函數,其形參為本類對象的引用。class類名{public:

類名(形參);//構造函數類名(類名&對象名);//拷貝構造函數

……};類名::類名(類名&對象名)//拷貝構造函數的實現{函數體}16拷貝構造函數舉例classCCircle{public:

CCircle(floatm=1,floatn=1,floatr=1);

CCircle(constCCircle&c)//拷貝構造函數

{ radius=c.radius; }……};17當用類的一個對象去初始化該類的另一個對象時系統自動調用它實現對象的拷貝賦值。voidmain(){

CCirclec1;

CCircle

c2(c1);//拷貝構造函數被調用}拷貝構造函數調用之一18拷貝構造函數調用之二若函數的形參為類對象按值傳遞時,實參賦值給形參,將自動調用復制構造函數,例如:voidfun1(CCirclec){

cout<<c.GetRadius()<<endl;}voidmain(){

CCirclec1(2,2,10);fun1(c1);//調用復制構造函數

}

19當函數的返回值是類對象時,系統自動調用復制構造函數。例如:CCirclefun2(){

CCirclec2(10);returnc2;//調用復制構造函數}voidmain(){

CCirclec3;c3=fun2();}拷貝構造函數調用之三20對于任何類,如果程序員沒有定義拷貝構造函數,則系統自動生成一個拷貝構造函數,這種拷貝構造函數在執行時,只是進行簡單的成員復制,這對于含有指針成員的類是非常危險的,在這種情況下,必須自定義拷貝構造函數。拷貝構造函數說明212.2.3析構函數作用:是釋放對象所占的動態內存空間。

特點:函數名:~類名();沒有參數,也不返回任何值不允許重載如果類中未定義析構函數,編譯器將自動生成一個缺省的析構函數。形如:~類名(){}22在下列兩種情況下會被自動調用:

對象定義在一個函數體中,該函數調用結束后,自動調用析構函數;用new生成的動態對象,當使用delete刪除時,自動調用析構函數。通常利用析構函數刪除對象中指針成員所指向的動態存儲空間,當類中沒有指針成員時,則不需要定義析構函數。析構函數的調用232.2.4對象的定義和使用類的對象是該類的某一特定實體,即類類型的變量。聲明形式:

類名對象名;例:

CCircleC1;

CCircle*pCircle;

CCircle

ArrayCircle[3];24類成員的訪問方式類內成員互訪直接使用成員名可以訪問任意屬性成員類外訪問只能訪問

public

屬性的成員使用“對象名.成員名”方式使用“對象指針名->成員名”方式25classTime{public:

inthour;

intminute;};Timet,*p;p=&t;cout<<p->hour;p->hour(*p).hourt.hour26this指針在C++中為每個非靜態成員函數提供了一個名字為this的指針,當進行成員函數調用時,系統自動將調用此成員函數的對象的地址作為一個隱含的參數傳遞給this指針,即讓this指針指向調用此成員函數的對象,從而使成員函數知道該對哪個對象進行操作。使用this指針,保證了每個對象可以擁有不同的數據成員,但處理這些數據成員的代碼可以被所有的對象共享。27例2.2類的應用舉例(教材28頁)一圓型游泳池如圖所示,現需要在其周圍建一圓型過道,并在其四周圍上柵欄。柵欄價格為35元/米,過道造價為20元/平方米。過道寬度為3米,游泳池半徑由鍵盤輸入。要求編程計算并輸出過道和柵欄的造價。游泳池過道282.2.5靜態類成員

創建了一個對象,則這個對象將擁有所有類中的成員,如果某個數據對所有對象都一樣,則這個數據只要有一個拷貝,而不是每個對象都重復定義這個數據,形成內存浪費。簡言之:一個數據拷貝,所有對象共享。這時可以使用靜態數據成員。靜態類成員:使用關鍵字static進行修飾的類成員。靜態類成員可以聲明為public、private或

protected。

291、靜態數據成員表示的是類范圍中所有對象共享的信息,相當于局部于類中的“全局變量”,為該類的所有對象共享。因為靜態數據成員只有一個數據副本,所以可以節省存儲空間。2、靜態數據成員必須在文件作用域內進行初始化,而且只能初始化一次。1、靜態數據成員3、由于數據隱藏的需要,靜態數據成員通常被聲明為

私有的,而通過定義公有的靜態成員函數來訪問靜態數據成員。30靜態數據成員的定義和初始化classCCircle{public:……private:……

staticint

NumOfObject;//程序中生成的對象的個數};intCCircle::NumOfObject=0;//靜態數據成員的初始化31

靜態成員函數:是用關鍵字static進行修飾的成員函數。

靜態成員函數沒有this指針,因此當其訪問非靜態數據成員時,必須通過對象名或對象指針訪問。2、靜態成員函數定義格式:static成員函數的原型;32使用靜態類成員(教材30頁)

3、靜態成員的訪問在類內:可直接訪問。在類外:只能訪問公有靜態成員類名::成員名(常用)對象名.成員名(.和->)332.3繼承性和派生類繼承是面向對象程序設計的最重要的特點之一,是軟件重用的一種重要形式,是對實際問題中分層特性的一種自然描述。繼承的實質:是從已有的類建立新類。通過繼承,派生類自動擁有基類的所有成員(數據成員和成員函數)基類和派生類單繼承和多繼承

342.3.1派生類的定義class派生類名:繼承方式基類名{

成員聲明;};35繼承方式三種繼承方式:public(公有)、

private(私有)、

protected(保護),

表2-1繼承方式對派生類的影響繼承方式說

明public(公有)基類的public和protected成員被派生類繼承后,保持原來的訪問屬性不變private(私有)基類的public和protected成員被派生類繼承后,變成派生類的private成員protected(保護)基類的public和protected成員被派生類繼承后,變成派生類的protected成員36例2.3

類的派生示例教材31頁

372.3.2派生類的構造函數與析構函數基類的構造函數不能被繼承,需要在派生類中負責基類成員的初始化。通過在成員初始化表中顯式調用基類的構造函數來實現的單一繼承時的構造函數派生類名::派生類名(基類成員和本類成員所需的形參):基類名(實參){

本類成員初始化;}38派生類構造函數與析構函數的執行順序在創建派生類的對象時,派生類的構造函數總是先調用其基類的構造函數來完成基類成員的初始化。如果在基類和派生類中都包含其他類的對象(即有對象成員),則在創建派生類的對象時,首先執行基類的對象成員的構造函數,接著執行基類的構造函數,然后執行派生類的對象成員的構造函數,最后才執行派生類的構造函數。當派生類對象的生命周期結束時,析構函數的執行順序和構造函數的執行順序正好相反。392.3.3多繼承如果一個派生類有多個直接基類,則稱為多繼承。多繼承意味著一個派生類可以繼承多個基類的成員,這種強大的功能支持了軟件的重用性,但可能會引起大量的二義性(歧義性)問題。

401.多繼承的定義格式class<派生類名>:[<繼承方式>]<基類名>,[<繼承方式>]<基類名>,…{[<派生類的成員>]};其中,繼承方式的使用與單繼承完全相同。【例2.4】使用多繼承(教材35頁)412.多繼承派生類對象的初始化派生類構造函數名(總參數表列):基類1構造函數(參數列表),基類2構造函數(參數列表),基類3構造函數(參數列表){派生類中新增數據成員初始化語句}先調用基類的構造函數,再執行派生類構造函數的函數體。調用基類構造函數的順序是按照聲明派生類時基類出現的順序。423.二義性問題因不同基類中可能含有同名成員引起的二義性:用基類名加以限定,形如:基類名::同名成員名,以明確指出所使用的成員是從哪個基類繼承來的。因公共基類使得派生類中含有同名成員,因此也會產生二義性。為了消除這種二義性,也必須使用基類名限定所訪問的同名成員。43虛基類解決多繼承中因公共基類而產生的二義性問題。聲明虛基類的一般格式為:class<派生類名>:virtual[<繼承方式>]<基類名>{[<派生類的成員>]};保留字virtual和繼承方式的相對位置無關緊要,但要放在基類名之前,并且virtual只對緊跟其后的基類名起作用。442.4多態性在面向對象的程序設計中,把不同類的對象收到相同的消息時產生多種不同的行為方式稱為多態性。452.4.1兩種多態性聯編:將一個函數調用鏈接上相應于函數體的代碼,這一過程稱為函數聯編(簡稱聯編)。靜態聯編:在編譯階段完成;優點是執行速度快動態聯編:在運行時才能把函數調用與函數體聯系在一起。具有靈活性高,易于擴充和維護等優點,但運行效率較低。靜態聯編所支持的多態性稱為編譯時的多態性,通過函數重載來實現。動態聯編所支持的多態性稱為運行時的多態性,通過虛函數來實現。462.4.2編譯時的多態性【例2.6】編譯時的多態性(教材39頁)472.4.3虛函數虛函數是實現動態聯編的基礎。虛函數的聲明:在函數原型之前加virtual。class<類名>{public:

//虛函數的聲明

virtual<返回類型><函數名>(<參數表>);};

//虛函數的定義<返回類型><類名>::<函數名>(<參數表>)

{…...}

48應注意的問題:應該在類層次結構中需要多態性的最高層類內聲明虛函數。派生類中與基類虛函數原型完全相同的成員函數,會自動成為虛函數。不能把靜態成員函數、構造函數和全局函數聲明為虛函數。析構函數可以聲明為虛函數。通過聲明虛函數來使用C++提供的多態性機制時,派生類應該從它的基類公有派生。

492.使用虛函數必須合理調用虛函數才能實現動態聯編。只有使用基類類型的指針或引用調用虛函數時,系統才以動態聯編方式實現對虛函數的調用,才能獲得運行時的多態性。通常都用指向第一次定義虛函數的基類對象的指針或引用來調用虛函數。虛函數的使用(教材41頁)503.純虛函數純虛函數:在聲明時“初始化值”為0的函數。class<類名>{public:virtual<返回類型><函數名>(<參數表>)=0;};純虛函數不需要進行定義51抽象類帶有純虛函數的類稱為抽象類。不能聲明抽象類的對象,但可以聲明抽象類的指針和引用。抽象類只能作為基類來使用。522.5友元類的重要特性是對數據實現了封裝和隱藏,這樣能大大提高程序的質量,特別是能夠提高軟件的可維護性。封裝也會帶來一些不便。如果在程序中為了訪問對象的私有數據成員而頻繁調用公有成員函數時,將會帶來較大開銷,從而降低程序的執行效率,影響程序的性能。C++中引入了友元機制,一個類可以賦予某些函數或類(友元函數或友元類)訪問它的私有成員的特權,從而減少了開銷。532.5.1友元函數能夠訪問一個類的私有部分而又不是該類成員函數的函數,稱為該類的友元函數。將一個函數聲明為類的友元,就是在類定義中該函數的原型前面加上關鍵字friend。如下所示:classA{friendvoidsetX(A&,int

);…};54友元函數說明友元函數雖然在類內聲明,但它不是該類的成員函數,所以友元函數沒有this指針。友元關系的聲明與成員訪問說明符private、protected和public無關,因此友元函數聲明可以放在類定義中的任何地方。【例2.8】使用友元函數計算兩點間的距離。55友元成員一個類的成員函數也可以聲明為另一個類的友元函數。把類C1的成員函數func聲明為類C2的友元函數:classC1{

…voidfunc(…);

…};classC2{friendvoidC1::func(…);//聲明友元成員

…};voidC1::func(…)

//定義友元成員{…}562.5.2友元類如果一個類的所有成員函數都可以訪問另一個類的私有成員,則可以把這個類聲明為另一個類的友元類。例如,把類C1聲明為類C2的友元類:

classC2{friendclassC1;

…};【例2.9】使用友元類(教材47頁)572.6模板模板是C++實現軟件重用的一種形式,是C++最強大的特性之一。利用模板,我們可以用一段代碼指定一組相關函數(稱為模板函數)或一組相關類(稱為模板類)。這樣能大幅度地節約程序代碼,顯著減少冗余信息,從而進一步提高面向對象程序的可重用性和可維護性。模板的功能很強,用戶既可以定義類模板,也可以定義函數模板,還可以使用C++標準模板庫(STL)中已有的模板。

582.6.1函數模板如果幾個函數的功能相同,實現算法也相同,只是所處理的數據的類型不同,使用函數模板更簡潔,更方便。1.函數模板的定義

template<class<數據類型參數表>>

函數模板定義體59說明template是C++的保留字,表示后面定義的是一個模板。<數據類型參數表>形如<classT1,classT2,…>,T1,T2等是類型參數(形式參數),函數模板定義體與普通函數的定義相同,只不過其中的有些數據類型,例如返回值類型,形參的類型,局部變量的類型等,要使用類型參數表中的標識符T1,T2等表示。602.函數模板的調用函數模板的調用格式有兩種:第一種格式:函數模板名(實參表)第二種格式:函數模板名<類型實參

>(實參表)函數模板的調用過程:函數模板實例化,把模板的類型參數T1,T2等用具體的數據類型去替換。函數模板實例化后會得到一個具體的函數,該函數稱為模板函數。執行模板函數,完成所需要的功能。【例2.10】利用函數模板實現求兩個數據的較大值。(教材50頁)613.函數模板的特點函數模板實際上代表了一組函數,而不是一個具體函數。所以,函數模板必須先實例化,才能完成具體函數的功能。函數模板不具有隱式類型轉換的能力。普通函數在進行調用時,如果實參的類型與形參的類型不同,則系統會自動對參數類型進行隱式轉換,將實參的值轉換為函數所需的類型(實際上是生成一個臨時值使用),然后再進行函數調用。而函數模板不具有這種功能。

622.6.2類模板1.定義類模板(1)定義類template<class<類型參數表>>class<類名>{…};(2)定義成員函數632.使用類模板類模板與函數模板一樣,也是代表一組類。因此在使用類模板時首先要把它實例化為一個具體的類,這個具體的類稱為模板類。把類模板實例化為模板類的格式如下:類名<具體數據類型名>然后用模板類聲明對象并使用這些對象完成所需要的功能。64#include<iostream>usingnamespacestd;template<classnumtype>classCompare{public:

Compare(numtype

a,numtypeb){x=a;y=b;}

numtypemax(){return(x>y)?x:y;}

numtypemin(){return(x<y)?x:y;}private:

numtype

x,y;};65intmain(){Compare<int>cmp1(3,7);

cout<<cmp1.max()<<"istheMaximumoftwointedernumbers."<<endl;

cout<<cmp1.min()<<"istheMinimumoftwointedernumbers."<<endl<<endl;Compare<float>cmp2(45.78,93.6);

cout<<cmp2.max()<<"istheMaximumoftwofloatnumbers."<<endl;

cout<<cmp2.min()<<"istheMinimumoftwofloatnumbers."<<endl<<endl;Compare<char>cmp3('a','A');

cout<<cmp3.max()<<"istheMaximumoftwocharacters."<<endl;

cout<<cmp3.min()<<"istheMinimumoftwocharacters."<<endl;return0;}663.模板與繼承(1)從類模板派生出類模板

template<classT>classCBase{

…};template<classT>classCDerived

:publicCBase<T>{

…};(2)從類模板派生出普通類template<classT>classCBase{

…};classCDerived

:publicCBase<int>{

…};67——獲取水仙花數

1.項目要求編寫一個程序,獲取指定數是否為水仙花數。水仙花數應該滿足下面條件:一個3位數,其各位數字的立方和等于該數本身。例如,153是一個水仙花數,因為153=13+53+33。該程序要求可以判斷用戶輸入的數是否為水仙花數,也可以獲取指定范圍內的數(在100至10000內)是否為水仙花數。2.項目分析如果判斷一個數是否是水仙花數,需要獲取該數每位的數值。這可以通過求余數的方法獲取每位的數值,然后獲取每位的立方并求和。通過將和值與該數進行比較,可以判斷該數是否為水仙花數。

68——獲取水仙花數

3.項目實現創建一個工程Exam,該程序由類Data判斷數是否為水仙花數,并輸出。這就需要創建類Data,該類擁有兩個私有屬性:num和ntype。num為用戶輸入的數,ntype為用戶選擇的操作類型。ntype有以下兩種類型。判斷用戶輸入的數是否為水仙花數。獲取指定范圍內(在100~10000內)的水仙花數。

69類Data含有5個成員函數,說明如下。Data(intnum):Data構造函數,參數num為用戶輸入的數。該函數需要初始化ntype為1。Data():Data構造函數,獲取指定范圍內(在100~10000內)的水仙花數。該函數需要初始化ntype為2。GetResult():函數依據ntype執行相應的操作,并輸出結果。IsSpecial(int

nNum):判斷nNum是否為水仙花數,是則返回t

溫馨提示

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

評論

0/150

提交評論