C#繼承---理解與分析


在這篇文章中,我們會用示例討論C#繼承。繼承是面向對象編程的一項原則,這項原則解決了可擴展性問題。在這篇文章中,我們會討論以下幾點:

1、什么是繼承?

2、繼承的類型;

3、為什么需要繼承?

4、如何在應用程序中使用繼承?

一、繼承是什么?

從已存在的類中創建一個新類,這樣新類就獲得了已存在類的所有屬性和行為,這一過程就叫做繼承。傳送屬性(或行為)的類,叫做超類或父類或基類,而自超類繼承屬性或行為的類叫做子類或派生類(derived class)。總之一句話,繼承意味着從已經完成或已經現有的可利用的方面取得某些東西。

繼承是一種代碼可復用性和可改變性為目的的概念。這里所指的可改變性意味着可以重載對象的已有功能或特征,或是給對象添加更多的功能。

C#.NET支持的繼承類別

C#.NET將繼承划分為兩大類:

1、實現繼承(Implementation inheritance

2、接口繼承(Interface inheritance

二、繼承的類型

繼承分為5種類型,它們分別如下:

1、單一繼承(Single Inheritance):當一個類是從單個基類繼承而來,這種繼承關系叫單一繼承;

 

 

 

2、多級繼承(Multilevel Inheritance):當一個派生類是從另一個派生類創建的,這種繼承關系叫多級繼承;

 

 

 

3、同級繼承(Hierarchical Inheritance):當多個派生類是從同一基類創建的,這種繼承關系叫同級繼承;

 

 

 4、混合繼承(Hybrid Inheritance):混合繼承是任意單繼承、同級繼承和等級繼承的組合;

 

 5、多重繼承(Multiple Inheritance):當一個派生類創建於多個基類,這種繼承類型叫多重繼承。但是在.NET中,類是不能多重繼承的,但是接口可以多重繼承的。

 

 注:處理由多重繼承引起的復雜性是非常復雜的,因此在.net中,類是不支持多重繼承的,而接口可以支持多重繼承。

 C#中使用繼承需要考慮的規則

規則1:在繼承中,對於子類來說,父類的構造函數必須易於訪問,否則繼承就不成立,因為當我們創建子類對象時,它會運行並調用父類的構造函數,這樣父類變量會被初始化,我們就可以在子類中使用它們。

示例如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Drawing;
 6 using System.Windows.Forms;
 7 
 8 namespace parent_and_child_class
 9 {
10     //創建父類Person和子類Student
11     public class Person
12     {
13         public Person()
14         {
15             Console.WriteLine("我是人");
16         }
17     }
18 
19     public class Student : Person
20     {
21         public Student()
22         {
23             Console.WriteLine("我是學生");
24         }
25     }
26 
27     //在客戶端通過子類無參構造函數創建子類實例
28     class Program
29     {
30         static void Main(string[] args)
31         {
32             Student student = new Student();
33 
34             Console.ReadKey();
35         }
36     }
37 }

 

 結論:通過調用子類無參構造函數創建子類實例,會默認調用父類無參構造函數。

規則2:在繼承中,子類能使用父類成員,但父類不能完全使用在子類中定義的成員。

注: 我們習慣認為,子類對父類是不可見的,或者說父類不知道子類的存在,所以父類是調用不到子類的方法、屬性的。

規則3:一個類的對象可以做為引用被分配給同一個類的變量,一個類的對象也可以做為引用分配給父類的變量,這樣引用開始分配給它的對象內存,但是現在也可以使用我們控制的引用來訪問子類的純成員。

注:父類對象不能分配給子類變量。通過顯式轉換,用子類對象創建的父類引用可以轉換回子類引用。

為什么我們需要繼承?

 

 我們用示例來理解為什么需要繼承。假設一家公司有“n”個分支機構,要求將公司分支機構詳細信息電腦化,然后我們創建Class Branch類,此類包含data成員BranchCode, BranchName, 和 BranchAddress;還有函數 GetBranchData() 和 DisplayBranchData().。

一段時間后,公司還要求將每個分支機構的雇員詳細信息電腦化。然后我們創建了Class Employee,此類包含成員 EmployeeId, EmployeeName, EmployeeAddress, EmployeeAge,還有函數 GetEmployeeData() 和 DisplayEmployeeData().。

如果我們在沒有使用繼承的情況下創建這兩個類,我們需要獨立地分別地為每個類創建對象,像下面這樣:

Obj1是Class Branch類的對象,Obj2是Employee類的對象。很難分辨哪個employee屬於哪個分支機構。所以如果我們從Branch類派生出Employee類,我們再創建派生類Employee的對象,它會代表兩個類,會保持對基類和派生類成員的引用。

示例:

 1 namespace InheritanceDemo
 2 {
 3     class Branch
 4     {
 5         int BranchCode;
 6         string BranchName, BranchAddress;
 7         public void GetBranchData()
 8         {
 9             Console.WriteLine("ENTER BRANCH DETAILS:");
10             Console.WriteLine("ENTER BRANCH CODE");
11             BranchCode = int.Parse(Console.ReadLine());
12             Console.WriteLine("ENTER BRANCH NAME");
13             BranchName = Console.ReadLine();
14             Console.WriteLine("ENTER BRANCH ADDRESS");
15             BranchAddress = Console.ReadLine();
16         }
17         public void DisplayBranchData()
18         {
19             Console.WriteLine("BRANCH CODE IS : " + BranchCode);
20             Console.WriteLine("BRANCH NAME IS : " + BranchName);
21             Console.WriteLine("BRANCH ADDRESS IS : " + BranchAddress);
22         }
23     }
24     class Employee : Branch
25     {
26         int EmployeeId, EmployeeAge;
27         string EmployeeName, EmployeeAddress;
28         public void GetEmployeeData()
29         {
30             Console.WriteLine("ENTER EMPLYEE DETAILS:");
31             Console.WriteLine("ENTER EMPLOYEE ID");
32             EmployeeId = int.Parse(Console.ReadLine());
33             Console.WriteLine("ENTER EMPLOYEE AGE");
34             EmployeeAge = int.Parse(Console.ReadLine());
35             Console.WriteLine("ENTER EMPLOYEE NAME");
36             EmployeeName = Console.ReadLine();
37             Console.WriteLine("ENTER EMPLOYEE ADDRESS");
38             EmployeeAddress = Console.ReadLine();
39         }
40         public void DisplayEmployeeData()
41         {
42             Console.WriteLine("EMPLOYEE ID IS : " + EmployeeId);
43             Console.WriteLine("EMPLOYEE NAME IS : " + EmployeeName);
44             Console.WriteLine("EMPLOYEE ADDRESS IS : " + EmployeeAddress);
45             Console.WriteLine("EMPLOYEE AGE IS : " + EmployeeAge);
46         }
47     }
48     class Program
49     {
50         static void Main(string[] args)
51         {
52             Employee obj1 = new Employee();
53             obj1.GetBranchData();
54             obj1.GetEmployeeData();
55             obj1.DisplayBranchData();
56             obj1.DisplayEmployeeData();
57             Console.WriteLine("Press any key to exist.");
58             Console.ReadKey();
59         }
60     }
61 }

在上面的例子中,我們將Branch類的GetEmployeeData() 和 DisplayEmployeeData() 設置為public,是因為外部的Employee類可以訪問這些函數。數據字段BranchCode, BranchName, 和 BranchAddress設置為private(默認),這樣只有在同一個類內才可以訪問。

但是,如果不想讓非繼承類訪問基類成員(在此例子中是Program類),而對於繼承類(Employee類)來說可以訪問基類,這時我們可以使用protected關鍵詞。

將public更換為protected后,示例如下:

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Drawing;
 6 using System.Windows.Forms;
 7 
 8 namespace Employee_and_Branch
 9 {
10     class Branch
11     {
12         int BranchCode;
13         string BranchName, BranchAddress;
14         protected void GetBrandhData()
15         {
16             Console.WriteLine("enter branch details");
17             Console.WriteLine("enter branch code");
18             BranchCode = int.Parse(Console.ReadLine());
19             Console.WriteLine("enter branch name");
20             BranchName = Console.ReadLine();
21             Console.WriteLine("enter branch address");
22             BranchAddress = Console.ReadLine();
23         }
24         protected void DisplayBranchData()
25         {
26             Console.WriteLine("branch code is :" + BranchCode);
27             Console.WriteLine("branch name is :" + BranchName);
28             Console.WriteLine("branch address is :" + BranchAddress);
29         }
30     }
31 
32     class Employee : Branch
33     {
34         int EmployeeId, EmployeeAge;
35         string EmployeeName, EmployeeAddress;
36         public void GetEmployeeData()
37         {
38             Console.WriteLine("enter emplyee details");
39             Console.WriteLine("enter employee id");
40             EmployeeId = int.Parse(Console.ReadLine());
41             Console.WriteLine("enter employee age");
42             EmployeeAge = int.Parse(Console.ReadLine());
43             Console.WriteLine("enter employee name");
44             EmployeeName = Console.ReadLine();
45             Console.WriteLine("enter employee address");
46             EmployeeAddress = Console.ReadLine();
47         }
48         public void DisplayEmployeeData()
49         {
50             Console.WriteLine("employee id is :" + EmployeeId);
51             Console.WriteLine("employee name is :" + EmployeeName);
52             Console.WriteLine("employee address is :" + EmployeeAddress);
53             Console.WriteLine("employee age is :" + EmployeeAge);
54         }
55     }
56 
57     class Program
58     {
59         static void Main(string[] args)
60         {
61             Employee obj1 = new Employee();
62             obj1.GetBrandhData();
63             obj1.GetEmployeeData();
64             obj1.DisplayBranchData();
65             obj1.DisplayEmployeeData();
66             Console.WriteLine("press any key to exist.");
67             Console.ReadKey();
68         }
69     }
70 }

 

以上代碼會報錯,具體如下:

 

 

 1 namespace InheritanceDemo
 2 {
 3     class Branch
 4     {
 5         int BranchCode;
 6         string BranchName, BranchAddress;
 7         protected void GetBranchData()
 8         {
 9             Console.WriteLine("ENTER BRANCH DETAILS:");
10             Console.WriteLine("ENTER BRANCH CODE");
11             BranchCode = int.Parse(Console.ReadLine());
12             Console.WriteLine("ENTER BRANCH NAME");
13             BranchName = Console.ReadLine();
14             Console.WriteLine("ENTER BRANCH ADDRESS");
15             BranchAddress = Console.ReadLine();
16         }
17         protected void DisplayBranchData()
18         {
19             Console.WriteLine("BRANCH CODE IS : " + BranchCode);
20             Console.WriteLine("BRANCH NAME IS : " + BranchName);
21             Console.WriteLine("BRANCH ADDRESS IS : " + BranchAddress);
22         }
23     }
24     class Employee : Branch
25     {
26         int EmployeeId, EmployeeAge;
27         string EmployeeName, EmployeeAddress;
28         public void GetEmployeeData()
29         {
30             //to call the base class method use base keyword
31             base.GetBranchData();
32             Console.WriteLine("ENTER EMPLYEE DETAILS:");
33             Console.WriteLine("ENTER EMPLOYEE ID");
34             EmployeeId = int.Parse(Console.ReadLine());
35             Console.WriteLine("ENTER EMPLOYEE AGE");
36             EmployeeAge = int.Parse(Console.ReadLine());
37             Console.WriteLine("ENTER EMPLOYEE NAME");
38             EmployeeName = Console.ReadLine();
39             Console.WriteLine("ENTER EMPLOYEE ADDRESS");
40             EmployeeAddress = Console.ReadLine();
41         }
42         public void DisplayEmployeeData()
43         {
44             base.DisplayBranchData();
45             Console.WriteLine("EMPLOYEE ID IS : " + EmployeeId);
46             Console.WriteLine("EMPLOYEE NAME IS : " + EmployeeName);
47             Console.WriteLine("EMPLOYEE ADDRESS IS : " + EmployeeAddress);
48             Console.WriteLine("EMPLOYEE AGE IS : " + EmployeeAge);
49         }
50     }
51     class Program
52     {
53         static void Main(string[] args)
54         {
55             Employee obj1 = new Employee();
56             //Here we cannot access the Branch class method as they are now protected
57             // obj1.GetBranchData(); //Will give Compile time error
58             obj1.GetEmployeeData();
59             // obj1.DisplayBranchData(); // will give compile time error
60             obj1.DisplayEmployeeData();
61             Console.WriteLine("Press any key to exist.");
62             Console.ReadKey();
63         }
64     }
65 }

以上是正確的示例代碼。

一般地,當我們開發應用程序的時候,遵循以下過程:

1、識別與應用程序相關聯的實體;

2、識別與應用程序相關聯的特性;

3、現在,按層次順序分離每個實體的屬性,而不存在任何重復項;

4、將這些實體轉換為類;

示例:

我們用一個運行時的例子來了解一下繼承。假設我們正在為學校開發應用程序,實體的屬性如下所示:

現在,基於以下層級關系來分離實體的屬性。

現在定義表示實體的類,如下所示

 1 namespace InheritanceDemo
 2 {
 3     public class Person
 4     {
 5         int Id;
 6         string Name;
 7         string Address;
 8         string Phone;
 9     }
10     public class Student : Person
11     {
12         string Class;
13         string Fees;
14         string Marks;
15         string Grade;
16     }
17     public class Staff : Person
18     {
19         string Designation;
20         double Salary;
21     }
22     public class Technical : Staff
23     {
24         string Qualification;
25         string Subject;
26     }
27     public class NonTechnical : Staff
28     {
29         string Dname;
30         string Superior;
31     }
32 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM