【c#技術】第7章 面向對象的程序設計
本章要點:
? 面向對象的基本概念
? 類的定義與對象的聲明
? 構造函數(shù)和析構函數(shù)
? 類的靜態(tài)成員和實例成員
? 方法重載及運算符重載的編程實現(xiàn)
? 類的繼承與多態(tài)性的編程實現(xiàn)
? 類的屬性的實現(xiàn)
7.1 循序漸進學理論
7.1.1 面向對象程序設計概述
1.面向對象程序設計的由來
面向對象的程序設計是一種基于結構分析的、以數(shù)據(jù)為中心的程序設計方法。面向對象的程序設計方法總體思路是:將數(shù)據(jù)及處理這些數(shù)據(jù)的操作都封裝(Encapsulation)到一個稱為類(Class)的數(shù)據(jù)結構中,在程序中使用的是類的實例——對象。對象是代碼與數(shù)據(jù)的集合,是封裝好了的一個整體,對象具有一定的功能。也就是說對象是具有一定功能的程序實體。程序是由一個個對象構成的,對象之間通過一定的“相互操作”傳遞消息,在消息的作用下,完成特定的功能。
2.面向對象程序設計的基本概念
(1)類和對象
通常把具有同樣性質和功能的東西所構成的集合叫作類。
(2)屬性、方法與事件
屬性是對象的狀態(tài)和特點。
方法是對象能夠執(zhí)行的一些操作,它體現(xiàn)了對象的功能。
事件是對象能夠識別和響應的某些操作。
(3)封裝
所謂的封裝,就是將用來描述客觀事物的一組數(shù)據(jù)和操作組裝在一起,形成一個類。
(4)繼承
類之間除了有相互交流或訪問的關系以外,還可能存在著一種特殊的關系,這就是繼承。在VisualC#中只支持單繼承,即一個派生類只能有一個基類。
(5)重載
重載指的是方法名稱一樣,但如果參數(shù)不同,就會有不同的具體實現(xiàn)。重載主要有兩類:方法重載及運算符重載。 ? ?
(6)多態(tài)性
所謂多態(tài)性就是在程序運行時,面向對象的語言會自動判斷對象的派生類型,并調用相應的方法。
7.1.2 類和對象的聲明
1.類的聲明
[格式]:[類修飾符]class 類名[:基類類名]
{
成員定義列表;
}
【例7-1】定義一個Student類,用來對學生的信息和功能進行描述。假設學生具有學號、姓名、年齡、性別、平均成績等特征,并且具有設置學生特征和顯示學生特征的功能。
2.對象的聲明
[格式]:類名 實例名=new類名([參數(shù)]);3.類的成員
(1)類成員的分類
類的具體成員如下。
? 常量:用來定義與類相關的常量值。
? 字段:類中的變量,相當于C++中的成員變量。
? 類型:用來定義只能在類中使用的局部類型。
? 方法:完成類中各種計算或功能的操作。
? 屬性:定義類的特征,并對它們提供讀、寫操作。
? 事件:由類產(chǎn)生的通知,用于說明發(fā)生了什么事情。
? 索引器:允許編程人員在訪問數(shù)組時,通過索引器訪問類的多個實例。又稱下標指示器。
? 運算符:定義類的實例能使用的運算符。
? 構造函數(shù):在類被實例化時首先執(zhí)行的函數(shù),主要是完成對象初始化操作。
? 析構函數(shù):在對象被銷毀之前最后執(zhí)行的函數(shù),主要是完成對象結束時的收尾操作。
(2)類成員的可訪問性
在編寫程序時,可以對類的成員使用不同的訪問修飾符,從而定義它們的訪問級別,即類成員的可訪問性(Accessibility)。
在C#中,根據(jù)類成員的可訪問性可以把類成員分成四類,分別是公有成員(public)、私有成員(private)、保護成員(protected)、內部成員(internal)。
(3)類的靜態(tài)成員和實例成員
類的成員又可以分成靜態(tài)成員和非靜態(tài)成員。在聲明成員時,如果在語句前加上static保留字,則該成員是靜態(tài)成員,如果沒有static保留字,則成員是非靜態(tài)成員。二者最重要的區(qū)別是:靜態(tài)成員屬于類所有,非靜態(tài)成員屬于類的實例所有,所以又稱實例成員。 ?
7.1.3 類的構造函數(shù)和析構函數(shù)
1.構造函數(shù)
構造函數(shù)主要用來為對象分配存儲空間,完成初始化操作(如給類的成員變量賦值等)。在C#中,類的構造函數(shù)遵循以下規(guī)定。
(1)構造函數(shù)的函數(shù)名和類的名稱一樣。
(2)當某個類沒有構造函數(shù)時,系統(tǒng)將自動為其創(chuàng)建構造函數(shù),這種構造函數(shù)稱為默認構造函數(shù)。如例7-2中默認的構造函數(shù)為:
Example1()
{
};
(3)構造函數(shù)的訪問修飾符總是public。如果是private,則表示這個類不能被實例化,這通常用于只含有靜態(tài)成員的類中。
(4)構造函數(shù)由于不需要顯式調用,因而不用聲明返回類型。
(5)構造函數(shù)可以帶參數(shù)也可以不帶參數(shù)。
2.析構函數(shù)
析構函數(shù)在對象銷毀時被調用,常用來釋放對象占用的存儲空間。析構函數(shù)具有以下特點。
(1)析構函數(shù)不能帶有參數(shù)。
(2)析構函數(shù)不能擁有訪問修飾符。
(3)不能顯式地調用析構函數(shù)。
(4)析構函數(shù)的命名規(guī)則是在類名前加上一個“~”號。如上例的Example1類的析構函數(shù)為:
~Example1()
{
};
(5)析構函數(shù)在對象銷毀時自動調用。
【例7-3】 類的構造函數(shù)和析構函數(shù)的演示。(程序代碼詳見例7-3)[執(zhí)行結果]

7.1.4 類的方法及方法的重載
1.方法的定義
[格式]:[方法修飾符] 返回值類型 方法名([參數(shù)列表])
{ 方法實現(xiàn)部分;
}
2.靜態(tài)方法和非靜態(tài)方法
對于靜態(tài)方法和非靜態(tài)方法,只需抓住以下幾點:(1)靜態(tài)方法屬于類所有,非靜態(tài)方法屬于類定義的對象所有;(2)非靜態(tài)方法可以訪問類中包括靜態(tài)成員在內的所有成員,而靜態(tài)方法只能訪問類中的靜態(tài)成員。
【例7-4】 靜態(tài)方法和動態(tài)方法的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-4)
[執(zhí)行結果]

3.參數(shù)數(shù)組
關于參數(shù)數(shù)組,需掌握以下幾點。
(1)若形參表中含一個參數(shù)數(shù)組,則該參數(shù)數(shù)組必須位于形參列表的最后;
(2)參數(shù)數(shù)組必須是一維數(shù)組;
(3)不允許將params修飾符與ref和out修飾符組合起來使用;
(4)與參數(shù)數(shù)組對應的實參可以是同一類型的數(shù)組名,也可以是任意多個與該數(shù)組的元素屬于同一類型的變量;
(5)若實參是數(shù)組則按引用傳遞,若實參是變量或表達式則按值傳遞。
【例7-5】 參數(shù)數(shù)組的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-5)
[執(zhí)行結果]

4.方法的重載
方法重載是指同樣的一個方法名,有多種不同的實現(xiàn)方法。方法重載的格式是在一個類中兩次或多次定義同名的方法,這些同名的方法包括從基類繼承而來的方法,這些方法名稱相同,但每個方法的參數(shù)類型或個數(shù)不同,從而便于在用戶調用方法時系統(tǒng)能夠自動識別應調用的方法。
【例7-6】 方法重載的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-6)
[執(zhí)行結果]

7.1.5 運算符重載
在C#中,運算符重載在類中進行聲明,聲明的格式如下。
[格式]:返回值類型 operator 運算符(運算對象列表)
? {
? ? ? 重載的實現(xiàn)部分;
? };
在C#中,可以重載的運算符主要有:
+ ?- ! ?~ ++ ?-- ?true ?false
* ?/ % ?& ?| ?^ ?<< ?>> ?== ?!= ?< ?> ?<= ?>=
不能重載的運算符有: ? .
= && ?|| ??: ?new ?typeof ?sizeof ?is
【例7-7】 運算符重載的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-7)
[執(zhí)行結果]

7.1.6 域與屬性
1.域
域又稱字段,它是類的一個成員,這個成員代表與對象或類相關的變量。域的定義格式如下。
[格式]:[域修飾符] 域類型 域名;
【例7-8】 域的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-8)
[執(zhí)行結果]

2.屬性
屬性是對現(xiàn)實世界中實體特征的抽象,它提供了一種對類或對象特性進行訪問的機制。屬性的聲明格式如下。
[格式]:[屬性修飾符] 類型說明符 屬性名 ?{訪問聲明}【例7-9】 屬性的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-9)
[執(zhí)行結果]
7.1.7 this關鍵字
this關鍵字用來引用類的當前實例,成員通過this關鍵字可以知道自己屬于哪一個實例。this關鍵字只能用在類的構造函數(shù)、類的實例方法中,在其它地方(如靜態(tài)方法中)使用this關鍵字均是錯誤的。
7.1.8 類的繼承
繼承是面向對象程序設計中實現(xiàn)代碼重用的重要機制之一,它起源于現(xiàn)實世界中事物之間的聯(lián)系。
類的繼承的基本格式與功能如下。
[格式]:
class 派生類類名:基類類名
{ ?成員聲明列表;
}
【例7-10】 類繼承的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-10)
[執(zhí)行結果]

7.1.9 多態(tài)性
多態(tài)性是指同一操作作用于不同類的實例,這些類對它進行不同的解釋,從而產(chǎn)生不同的執(zhí)行結果的現(xiàn)象。在C#中有兩種多態(tài)性:編譯時的多態(tài)性和運行時的多態(tài)性。
運行時的多態(tài)性是通過繼承和虛成員來實現(xiàn)的。運行時的多態(tài)性是指系統(tǒng)在編譯時不確定選用哪個重載方法,而是直到程序運行時,才根據(jù)實際情況決定采用哪個重載方法。
編譯時的多態(tài)性具有運行速度快的特點,而運行時的多態(tài)性則具有極大的靈活性。
【例7-11】 虛函數(shù)與多態(tài)性的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-11)
[執(zhí)行結果]

7.1.10 密封類與抽象類
把一個類聲明為密封類的原因是為了防止該類被其它類繼承,密封類的聲明方法是在類名前加上sealed修飾符。
抽象類表示一種抽象的概念,一般用于為派生類提供公共接口。在聲明類時,在類名前有abstract修飾符則表示該類為抽象類。抽象類只能作為其他類的基類,不能被實例化,在抽象類中可以包含抽象方法和抽象訪問器。
7.2 典型實例練能力
7.2.1 典型實例一:Time類的創(chuàng)建與演示【實例題目】
編寫一個名為Time1的類,該類能夠存放時間信息,并且具有設置時間和顯示時間的功能。然后編程對該類進行測試。測試界面如圖7-1所示。

7.2.2 典型實例二:復數(shù)“*”運算及復數(shù)值設置的實現(xiàn)
【實例題目】
編寫一個復數(shù)類,該復數(shù)類具有以下功能:(1)乘法運算的功能。如a和b分別是該復數(shù)類的兩個實例,則可以進行a*b的運算,運算結果是一個復數(shù),該復數(shù)是復數(shù)a和復數(shù)b的乘積。(2)對復數(shù)值進行設置的功能,有兩種設置方法,分別對復數(shù)的實部(虛部為0)進行設置、對復數(shù)的實部和虛部同時進行設置。然后編程進行驗證。驗證界面如圖7-2所示。

7.3 上機練習重應用
7.3.1 上機練習一:棧模型的實現(xiàn)
【練習題目】
棧是一種重要的數(shù)據(jù)結構,在內存中占用連續(xù)的存儲單元。棧有兩個端點,固定的棧底和浮動的棧頂。為指示棧頂位置還應設一個指示成員變量(稱為棧頂指示器)。棧有兩種基本操作:push(壓棧)和pop(出棧),壓棧是向棧頂位置寫入一個元素,然后使棧頂指示器加1,出棧是先使棧頂指示器減1,再把該位置的元素讀出來。棧及其操作模型如圖7-3所示,sp代表棧頂指示器。請編程實現(xiàn)棧的模型并對之進行測試,測試的界面如圖7-4所示。


7.3.2 上機練習二:從shape類派生出Rectangle、Circle等具體形狀類
【練習題目】
定義一個shape抽象類,利用它作為基類派生出Rectangle、Circle等具體形狀類,已知具體形狀類均具有兩個方法GetArea和GetPerim,分別用來求形狀的面積和周長。最后編寫一個測試程序對產(chǎn)生的類的功能進行驗證,驗證程序的運行界面如圖7-5所示。

