物件導向程式設計,類別,執行個體介紹

我被程式碼海扁 @codebeatme
閱讀 10:36·字數 3183·發佈 

物件導向程式設計

物件導向程式設計,不是簡單的定義變數和函式,而是一套更為複雜的程式碼組織方案,他傾向於以貼近現實或需求的某個事物為單位,完成其相關資料的儲存和功能的實作。比如,在人事管理系統中,你可以把員工視為一個單位,並編寫姓名,年齡,考核功能的程式碼。

雖然不需要全部,但支援物件導向程式設計的語言,應該具有以下的某些特點。

封裝
封裝是指物件可以遮蔽其包含的資料和功能,僅公開特定的部分。外部僅能通過此部分來存取物件中的資料和使用物件中的功能。比如,員工擁有工資層級,但外部不能直接修改,只能通過員工的考核功能來重新評定他。
繼承
繼承是指通過某種方式,一個物件可以以另一個物件為基礎,拓展新的資料和功能。比如,管理者從員工繼承,拓展了新的管理規劃功能。
多型
多型是指在繼承中,對於同一功能,物件可以擁有不同的實作。比如,同樣是考核功能,管理者考核的實作與員工不同。

為何使用物件導向程式設計?
試想僅采用變數和函式來完成一個超級複雜的專案,我們可能會擁有複雜的陣列,以及參數眾多的函式,這加大了維護的難度。物件導向程式設計緩解了這些情況,複雜的問題被分散在封裝,繼承,多型等特點中。

類別

類別是物件的設計藍圖,是物件的型別,他描述了物件包含哪些資料和功能。具現化後的類別就是物件,物件也被稱為類別的執行個體。當然,“執行個體”一詞並不局限於類別,他也適用於介面,結構等其他概念。

類別的成員

類別的成員用於表述具體的資料和功能,從形式上可以劃分為以下幾類,當然,某些語言可能會支援更多。

欄位/變數
類別的欄位用於儲存資料,在一些語言中,他也被稱為變數。
方法/程序
類別的方法用於完成某種運算,你可以將其視為類別所擁有的函式,在一些語言中,他也被稱為程序。
屬性
類別的屬性可用於限製或檢驗欄位的存取,對外部來說,屬性的用法與欄位類似,但實際上屬性是一種語法糖,其本質是方法。
建構子/建構函式
類別的建構子也被稱為建構函式,他給予了在建立物件時進行初始設定的機會,你可以使用其提供的參數來初始化欄位或屬性。建構子的名稱不能隨意指定,一般采用類別名或某種特定名稱,比如,Newconstructor等。

如果依據成員的歸屬,那麽類別的成員可以分為兩大類。

執行個體成員
執行個體成員需要通過執行個體才能存取,雖然出現在類別的定義中,但通過類別是無法直接使用他們的。這種運作方式可以讓每個執行個體擁有各自獨立的資料,就像每位員工都應該擁有自己的姓名一樣。
類別成員/靜態成員/共用成員
與執行個體成員不同,類別成員可以通過類別直接存取,類別成員也被稱為靜態成員或共用成員。

如果依據讀取及寫入規則,類別的某些成員可以細分為三種。

可讀取及寫入成員
可讀取及寫入成員允許讀取和寫入,對於屬性來說,需要擁有getset存取子。
唯讀成員
唯讀成員只允許讀取,對於屬性來說,只能擁有get存取子,對於欄位則需要擁有特定關鍵字,比如readonly
唯寫成員
唯寫成員只允許寫入,對於屬性來說,只能擁有set存取子。

下面展示了 C# 類別Employee,他包含了執行個體欄位namelevel,類別欄位Count,執行個體屬性Name,執行個體方法Evaluate,以及一個建構子。

classes.cs
// 關於員工的類別 Employee
class Employee
{
	// 類別欄位 Count,記錄建立過的 Employee 執行個體的個數
	public static int Count;
	// 欄位 name,表示員工姓名
	string name;
	// 欄位 level,表示員工工資層級
	protected int level;

// 屬性 Name,用於控製欄位 name 的存取 public string Name { get { return name; } set { // 員工姓名不接受沒有意義的字串 if (string.IsNullOrEmpty(name)) return;
name = value; Console.WriteLine($"員工改名為:{name}"); } }

// 方法 Evaluate,根據工作量評定員工的工資層級 public void Evaluate(int workload) { level = workload / 365; Console.WriteLine($"員工 {Name} 的工資層級為:{level}"); }
// 建構子,用於初始化員工 public Employee(string n) { // 由於類別欄位 Count 歸屬於類別而非某個執行個體,因此會一直累計 // 建立過的 Employee 執行個體的個數加 1 Count++; // 初始化員工姓名 name = n; } }

類別的成員存取層級

類別的成員存取層級用於控製成員的可存取性,一般分為私用,保護,公用三種,其具體效果可能因語言的不同而不同。

私用
存取層級為私用的成員,只能在定義他的類別或其執行個體中被存取。
保護
存取層級為保護的成員,在私用存取層級的基礎上,還可以被衍生類別或其執行個體存取。關於衍生類別,會在稍後給出說明。
公用
存取層級為公用的成員,可以在任何位置被存取。

對於之前例子中定義的Employee類別,成員CountName,Evaluate以及建構子的存取層級為公用,因此可在任意位置存取。

*.cs
// 具現化類別 Employee
Employee employee1 = new("小熊貓");
// 通過屬性修改員工姓名
employee1.Name = "浣熊";
// 使用年工作量 12345 評定員工
employee1.Evaluate(12345);
// 顯示建立過的 Employee 執行個體的個數
Console.WriteLine($"建立了 {Employee.Count} 個 Employee");

// 再次具現化類別 Employee Employee employee2 = new("大熊貓"); // 此時顯示的個數為 2 Console.WriteLine($"建立了 {Employee.Count} 個 Employee");
員工改名為:浣熊
員工 浣熊 的工資層級為:33
建立了 1 個 Employee
建立了 2 個 Employee

類別的繼承

一個類別可以繼承自另一個類別,這實作了物件導向程式設計的繼承性,被繼承的類別被稱為基底類別,父類別或超類別,而繼承自基底類別的類別,被稱為衍生類別或子類別。衍生類別擁有基底類別已定義的成員,並可在此基礎上新增自己的新成員。

衍生類別Manager繼承自Employee,雖然不能存取Employee的私用成員name,但他定義了一個新的公用方法Manage,並存取了Employee的非私用成員Namelevel

classes.cs
// 關於管理者的類別 Manager
class Manager : Employee
{
	// Manager 類別加入了新的方法 Manage
	public void Manage()
	{
		// 存取基底類別的非私用成員
		Console.WriteLine($"{Name} 來管理自己了,哦,看下工資層級?{level}");
	}

// 建構子,用於初始化管理者 public Manager(string n) : base(n) { } }
*.cs
// 具現化類別 Manager
Manager manager = new("老熊貓");
// 呼叫 Manager 類別定義的 Manage 方法
manager.Manage();
老熊貓 來管理自己了,哦,看下工資層級?0

什麽是類別的多級繼承?
多級繼承(Multilevel Inheritance)也被稱為多層繼承,是指某個衍生類別成為另一個類別的基底類別的行為。比如,類別B是類別A的衍生類別,同時還是類別C的基底類別。

什麽是類別的多重繼承?
多重繼承(Multiple Inheritance)是指一個類別從多個基底類別繼承的行為,這種行為會產生語意模糊問題,即同一個基底類別被同一個衍生類別多次繼承,導致衍生類別無法確定使用他們中的哪一個,在存取該基底類別成員的時候。需要指出,並非所有的語言都支援多重繼承。

什麽是類別的虛擬繼承?
類別的虛擬繼承主要用於解決多重繼承帶來的語意模糊問題,當一些類別采用虛擬繼承後,從這些類別多重繼承的衍生類別,將只擁有一份虛擬基底類別的成員。這裏的虛擬基底類別是指被虛擬繼承的基底類別。

在下面的 C++ 程式碼中,類別C多重繼承自類別B1B2,因此類C兩次繼承了類別A,在呼叫基底類別AShow方法時,將無法確定是選擇來自於B1A,還是B2A

classes.cpp
#include <iostream>

// 基底類別 A,擁有 Show 方法 class A { public: void Show() { std::cout << "A::Show" << std::endl; } };
// 衍生類別 B1,B2 均繼承自 A class B1 : public A { }; class B2 : public A { };
// 衍生類別 C,將繼承 A 兩次 class C : public B1, public B2 { };
// 建立執行個體,並呼叫 Show 方法 int main() { C c; // ERROR 無法確定呼叫哪個 A 的 Show 方法 c.Show(); }

調整程式碼,將類別B1B2改為虛擬繼承後,對方法Show的呼叫不再有問題。

classes.cpp
// 改為采用虛擬繼承的方式
class B1 : virtual public A
{
};
class B2 : virtual public A
{
};
A::Show

類別的多型

類別的多型主要體現在本質是方法的成員上,當然,這包括方法本身,多型的應用體現了不同物件對功能差異化的需求。

內容分類

程式碼

classes.cs·codebeatme/programming·GitHub
classes.cpp·codebeatme/programming·GitHub