本章要點:
面向對象的基本概念
類的定義與對象的聲明
構造函數和析構函數
類的靜態成員和實例成員
方法重載及運算符重載的編程實現
類的繼承與多態性的編程實現
類的屬性的實現
7.1 循序漸進學理論
7.1.1 面向對象程序設計概述
1.面向對象程序設計的由來
面向對象的程序設計是一種基於結構分析的、以數據為中心的程序設計方法。面向對象的程序設計方法總體思路是:將數據及處理這些數據的操作都封裝(Encapsulation)到一個稱為類(Class)的數據結構中,在程序中使用的是類的實例——對象。對象是代碼與數據的集合,是封裝好了的一個整體,對象具有一定的功能。也就是說對象是具有一定功能的程序實體。程序是由一個個對象構成的,對象之間通過一定的「相互操作」傳遞消息,在消息的作用下,完成特定的功能。
2.面向對象程序設計的基本概念
(1)類和對象
通常把具有同樣性質和功能的東西所構成的集合叫作類。
(2)屬性、方法與事件
屬性是對象的狀態和特點。
方法是對象能夠執行的一些操作,它體現了對象的功能。
事件是對象能夠識別和響應的某些操作。
(3)封裝
所謂的封裝,就是將用來描述客觀事物的一組數據和操作組裝在一起,形成一個類。
(4)繼承
類之間除了有相互交流或訪問的關係以外,還可能存在著一種特殊的關係,這就是繼承。在VisualC#中只支持單繼承,即一個派生類只能有一個基類。
(5)重載
重載指的是方法名稱一樣,但如果參數不同,就會有不同的具體實現。重載主要有兩類:方法重載及運算符重載。
(6)多態性
所謂多態性就是在程序運行時,面向對象的語言會自動判斷對象的派生類型,並調用相應的方法。
7.1.2 類和對象的聲明
1.類的聲明
[格式]:[類修飾符]class 類名[:基類類名]
{
成員定義列表;
}
【例7-1】定義一個Student類,用來對學生的信息和功能進行描述。假設學生具有學號、姓名、年齡、性別、平均成績等特徵,並且具有設置學生特徵和顯示學生特徵的功能。
2.對象的聲明
[格式]:類名 實例名=new類名([參數]);3.類的成員
(1)類成員的分類
類的具體成員如下。
常量:用來定義與類相關的常量值。
欄位:類中的變量,相當於C++中的成員變量。
類型:用來定義只能在類中使用的局部類型。
方法:完成類中各種計算或功能的操作。
屬性:定義類的特徵,並對它們提供讀、寫操作。
事件:由類產生的通知,用於說明發生了什麼事情。
索引器:允許編程人員在訪問數組時,通過索引器訪問類的多個實例。又稱下標指示器。
運算符:定義類的實例能使用的運算符。
構造函數:在類被實例化時首先執行的函數,主要是完成對象初始化操作。
析構函數:在對象被銷毀之前最後執行的函數,主要是完成對象結束時的收尾操作。
(2)類成員的可訪問性
在編寫程序時,可以對類的成員使用不同的訪問修飾符,從而定義它們的訪問級別,即類成員的可訪問性(Accessibility)。
在C#中,根據類成員的可訪問性可以把類成員分成四類,分別是公有成員(public)、私有成員(private)、保護成員(protected)、內部成員(internal)。
(3)類的靜態成員和實例成員
類的成員又可以分成靜態成員和非靜態成員。在聲明成員時,如果在語句前加上static保留字,則該成員是靜態成員,如果沒有static保留字,則成員是非靜態成員。二者最重要的區別是:靜態成員屬於類所有,非靜態成員屬於類的實例所有,所以又稱實例成員。
7.1.3 類的構造函數和析構函數
1.構造函數
構造函數主要用來為對象分配存儲空間,完成初始化操作(如給類的成員變量賦值等)。在C#中,類的構造函數遵循以下規定。
(1)構造函數的函數名和類的名稱一樣。
(2)當某個類沒有構造函數時,系統將自動為其創建構造函數,這種構造函數稱為默認構造函數。如例7-2中默認的構造函數為:
Example1()
{
};
(3)構造函數的訪問修飾符總是public。如果是private,則表示這個類不能被實例化,這通常用於只含有靜態成員的類中。
(4)構造函數由於不需要顯式調用,因而不用聲明返回類型。
(5)構造函數可以帶參數也可以不帶參數。
2.析構函數
析構函數在對象銷毀時被調用,常用來釋放對象佔用的存儲空間。析構函數具有以下特點。
(1)析構函數不能帶有參數。
(2)析構函數不能擁有訪問修飾符。
(3)不能顯式地調用析構函數。
(4)析構函數的命名規則是在類名前加上一個「~」號。如上例的Example1類的析構函數為:
~Example1()
{
};
(5)析構函數在對象銷毀時自動調用。
【例7-3】 類的構造函數和析構函數的演示。(程序代碼詳見例7-3)[執行結果]
7.1.4 類的方法及方法的重載
1.方法的定義
[格式]:[方法修飾符] 返回值類型 方法名([參數列表])
{ 方法實現部分;
}
2.靜態方法和非靜態方法
對於靜態方法和非靜態方法,只需抓住以下幾點:(1)靜態方法屬於類所有,非靜態方法屬於類定義的對象所有;(2)非靜態方法可以訪問類中包括靜態成員在內的所有成員,而靜態方法只能訪問類中的靜態成員。
【例7-4】 靜態方法和動態方法的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-4)
[執行結果]
3.參數數組
關於參數數組,需掌握以下幾點。
(1)若形參表中含一個參數數組,則該參數數組必須位於形參列表的最後;
(2)參數數組必須是一維數組;
(3)不允許將params修飾符與ref和out修飾符組合起來使用;
(4)與參數數組對應的實參可以是同一類型的數組名,也可以是任意多個與該數組的元素屬於同一類型的變量;
(5)若實參是數組則按引用傳遞,若實參是變量或表達式則按值傳遞。
【例7-5】 參數數組的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-5)
[執行結果]
4.方法的重載
方法重載是指同樣的一個方法名,有多種不同的實現方法。方法重載的格式是在一個類中兩次或多次定義同名的方法,這些同名的方法包括從基類繼承而來的方法,這些方法名稱相同,但每個方法的參數類型或個數不同,從而便於在用戶調用方法時系統能夠自動識別應調用的方法。
【例7-6】 方法重載的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-6)
[執行結果]
7.1.5 運算符重載
在C#中,運算符重載在類中進行聲明,聲明的格式如下。
[格式]:返回值類型 operator 運算符(運算對象列表)
{
重載的實現部分;
};
在C#中,可以重載的運算符主要有:
+ - ! ~ ++ -- true false
* / % & | ^ << >> == != < > <= >=
不能重載的運算符有: .
= && || ?: new typeof sizeof is
【例7-7】 運算符重載的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-7)
[執行結果]
7.1.6 域與屬性
1.域
域又稱欄位,它是類的一個成員,這個成員代表與對象或類相關的變量。域的定義格式如下。
[格式]:[域修飾符] 域類型 域名;
【例7-8】 域的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-8)
[執行結果]
2.屬性
屬性是對現實世界中實體特徵的抽象,它提供了一種對類或對象特性進行訪問的機制。屬性的聲明格式如下。
[格式]:[屬性修飾符] 類型說明符 屬性名 {訪問聲明}【例7-9】 屬性的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-9)
[執行結果]
7.1.7 this關鍵字
this關鍵字用來引用類的當前實例,成員通過this關鍵字可以知道自己屬於哪一個實例。this關鍵字只能用在類的構造函數、類的實例方法中,在其它地方(如靜態方法中)使用this關鍵字均是錯誤的。
7.1.8 類的繼承
繼承是面向對象程序設計中實現代碼重用的重要機制之一,它起源於現實世界中事物之間的聯繫。
類的繼承的基本格式與功能如下。
[格式]:
class 派生類類名:基類類名
{ 成員聲明列表;
}
【例7-10】 類繼承的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-10)
[執行結果]
7.1.9 多態性
多態性是指同一操作作用於不同類的實例,這些類對它進行不同的解釋,從而產生不同的執行結果的現象。在C#中有兩種多態性:編譯時的多態性和運行時的多態性。
運行時的多態性是通過繼承和虛成員來實現的。運行時的多態性是指系統在編譯時不確定選用哪個重載方法,而是直到程序運行時,才根據實際情況決定採用哪個重載方法。
編譯時的多態性具有運行速度快的特點,而運行時的多態性則具有極大的靈活性。
【例7-11】 虛函數與多態性的演示。請觀察並分析下列程序的執行結果。(程序代碼詳見例7-11)
[執行結果]
7.1.10 密封類與抽象類
把一個類聲明為密封類的原因是為了防止該類被其它類繼承,密封類的聲明方法是在類名前加上sealed修飾符。
抽象類表示一種抽象的概念,一般用於為派生類提供公共接口。在聲明類時,在類名前有abstract修飾符則表示該類為抽象類。抽象類只能作為其他類的基類,不能被實例化,在抽象類中可以包含抽象方法和抽象訪問器。
7.2 典型實例練能力
7.2.1 典型實例一:Time類的創建與演示【實例題目】
編寫一個名為Time1的類,該類能夠存放時間信息,並且具有設置時間和顯示時間的功能。然後編程對該類進行測試。測試界面如圖7-1所示。
7.2.2 典型實例二:複數「*」運算及複數值設置的實現
【實例題目】
編寫一個複數類,該複數類具有以下功能:(1)乘法運算的功能。如a和b分別是該複數類的兩個實例,則可以進行a*b的運算,運算結果是一個複數,該複數是複數a和複數b的乘積。(2)對複數值進行設置的功能,有兩種設置方法,分別對複數的實部(虛部為0)進行設置、對複數的實部和虛部同時進行設置。然後編程進行驗證。驗證界面如圖7-2所示。
7.3 上機練習重應用
7.3.1 上機練習一:棧模型的實現
【練習題目】
棧是一種重要的數據結構,在內存中佔用連續的存儲單元。棧有兩個端點,固定的棧底和浮動的棧頂。為指示棧頂位置還應設一個指示成員變量(稱為棧頂指示器)。棧有兩種基本操作:push(壓棧)和pop(出棧),壓棧是向棧頂位置寫入一個元素,然後使棧頂指示器加1,出棧是先使棧頂指示器減1,再把該位置的元素讀出來。棧及其操作模型如圖7-3所示,sp代表棧頂指示器。請編程實現棧的模型並對之進行測試,測試的界面如圖7-4所示。
7.3.2 上機練習二:從shape類派生出Rectangle、Circle等具體形狀類
【練習題目】
定義一個shape抽象類,利用它作為基類派生出Rectangle、Circle等具體形狀類,已知具體形狀類均具有兩個方法GetArea和GetPerim,分別用來求形狀的面積和周長。最後編寫一個測試程序對產生的類的功能進行驗證,驗證程序的運行界面如圖7-5所示。