程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#基本語法學習(五),

C#基本語法學習(五),

編輯:C#入門知識

C#基本語法學習(五),


繼承和多態

  面向對象方法中的繼承體現了現實世界中的“一般特殊關系”。基類代表一般性事物,而派生類是一種特殊的基類,是對基類的補充和細化。不同的派生類執行同一個方法時,會出現不同的行為,這就是多態。

 

實現繼承

  C#中用如下語法實現繼承:

  class 派生類:基類 {類的成員}

  eg:public class MyButton:System.Windows.Forms.Button {}

 

  C#中所有的類都是直接或間接從System.Object類派生來的,如果定義一個類時沒有指明基類,那麼這個類的基類就是System.Object。.NET Framework中所有的類都是直接或間接派生自System.Object,甚至包括像int、string等簡單的類型也是。

因此C#中所有的類都是直接或間接繼承自System.Object類,從而也都擁有System.Object類中所定義的公共成員。

  C#只允許一個類僅從一個類繼承,但是一個類可以同時從多個接口繼承。

 

  變量的定義類型和實際類型:

  定義變量時的類型叫定義類型。變量被賦予值時的類型叫實際類型。變量的定義類型與實際類型不一定相同。如下

1 object obj1, obj2;
2 
3 obj1 = 123;
4 obj2 = "Hello";

  obj1和obj2定義類型都為object,但obj1實際類型是int,obj2實際類型是string。變量的類型都可以通過System.Object的GetType方法獲得,GetType返回一個System.Type類型的對象,用於描述變量的類型信息。由於變量可以多次被賦值,所以變量的

  實際類型在程序運行過程中是可以動態改變的。如下:

 1         static void Main(string[] args)
 2         {
 3             object obj1, obj2, obj3;
 4 
 5             Console.WriteLine("定義三個object類型變量");
 6             obj1 = 123;
 7             Console.WriteLine("將obj1賦值為123");
 8             obj2 = "Hello";
 9             Console.WriteLine("將obj2賦值為\"Hello\"");
10             obj3 = DateTime.Now;
11             Console.WriteLine("將obj3賦值為當前時間");
12             Console.WriteLine("obj1的實際類型為: " + obj1.GetType().ToString());
13             Console.WriteLine("obj2的實際類型為: " + obj2.GetType().ToString());
14             Console.WriteLine("obj3的實際類型為: " + obj3.GetType().ToString());
15 
16             obj3 = new int[] { 1, 2, 3 };
17             Console.WriteLine("將obj3賦值為一個整形數組");
18             Console.WriteLine("obj3的實際類型為: " + obj3.GetType().ToString());
19 
20             Console.ReadKey();
21         }

  運行結果為:

定義三個object類型變量
將obj1賦值為123
將obj2賦值為"Hello"
將obj3賦值為當前時間
obj1的實際類型為: System.Int32
obj2的實際類型為: System.String
obj3的實際類型為: System.DateTime
將obj3賦值為一個整形數組
obj3的實際類型為: System.Int32[]

  從運行結果來看,3個變量的定義類型都為object,實際類型分別為Int32、String和DateTime,而且obj3實際類型發生了變化,從DateTime變為int[]。

 

  變量只能按照定義的類型來使用。上面例子中obj3定義類型為object,就只能當object類型來使用,雖然後面實際類型為int[],如果把obj3當int[]來使用那麼會報錯,如下:

1 obj3[0] = 1;//報錯

  

  基類和派生類之間的類型轉換

  派生類向基類的轉換是安全的,總可以成功;但是基類向派生類轉換時,只有當變量的實際類型是目標類型或或目標類型的派生類時,轉換才能成功,否則會拋出System.InvalidCastException異常。

 

  虛方法和多態

  如果基類和派生類都定義了相同的簽名的方法,那麼程序在運行時會調用那個方法呢?如下:

 1     class Mammal
 2     {
 3         public void bark()
 4         {
 5             Console.WriteLine("Mammal.bark()\t 哺乳動物叫聲各不相同");
 6         }
 7     }
 8 
 9     class Dog:Mammal
10     {
11         public void bark()
12         {
13             Console.WriteLine("Dog.bark()\t 狗的叫聲汪汪汪");
14         }
15     }
16 
17         static void Main(string[] args)
18         {
19             Mammal m = new Mammal();
20             Dog d = new Dog();
21 
22             Console.WriteLine("Main 調用 Mammal.bark()");
23             m.bark();
24 
25             Console.WriteLine("Main 調用 Dog.bark()");
26             d.bark();
27 
28             Console.ReadLine();
29         }

  運行結果

Main 調用 Mammal.bark()
Mammal.bark()    哺乳動物叫聲各不相同
Main 調用 Dog.bark()
Dog.bark()       狗的叫聲汪汪汪

  由結果可知調用Mammal類型變量的bark方法時Mammal類的bark方法被執行,調用Dog類的對象的bark方法時,Dog類的bark方法被執行。

 

  如果定義類型與實際類型不一致時,會怎麼樣呢?

1             Mammal m;
2             Dog d = new Dog();
3 
4             m = d;
5             m.bark();
6             d.bark();

  運行結果

Mammal.bark()    哺乳動物叫聲各不相同
Dog.bark()       狗的叫聲汪汪汪

  從運行結果可以看出,雖然m和d是同一個對象,但由於定義對象不同,掉用bark執行的代碼也不一樣。bark方法實際執行的代碼是由定義類型決定的。所以m.bark()調用Mammal的bark方法,d.bark()調用Dog的bark方法。

  

  在很多時候,開發人員並不希望程序這樣運行,而是希望程序能夠根據變量的實際類型來調用相應的方法。這樣對於同一個Mammal類型的變量m,當其實際類型為不同的派生類時,調用m.bark()方法會產生不同的行為,這就是多態。

  當基類和派生類都定義了相同簽名的方法時,C#允許開發人員明確指定哪個方法應該被調用。是根據定義類型調用方法還是根據實際類型調用方法,C#通過虛方法、方法重寫和方法隱藏實現這個功能。

  如果想讓程序在運行時根據變量的定義類型來決定調用那個方法,可以通過方法隱藏來實現;如果想讓程序實現多態性,即在運行時根據變量的實際類型調用相應的方法,那麼可以通過虛方法和方法重寫實現。

  

  定義方法時使用new關鍵字可以隱藏基類具有相同簽名的方法,語法如下:

  訪問修飾符 new 返回值類型 方法名(參數列表){方法體}

  上述代碼預定一個普通方法的唯一區別是多了一個new關鍵字,new關鍵字表明這個方法將隱藏基類中相同簽名的方法。new關鍵字可以放在訪問修飾符的前面或後面都可以。

 

  使用virtual關鍵字可以定義一個虛方法,虛方法可以在派生類中被重寫。定義虛方法語法如下:

  訪問修飾符 virtual 返回值類型 方法名(參數列表) {方法體}

  派生類使用override關鍵字重寫基類中的虛方法,語法如下:

  訪問修飾符 override 返回值類型 方法名(參數列表) {方法體}

  在基類中使用virtual關鍵字定義虛方法,在派生類中使用override關鍵字重寫虛方法,可以使程序呈現多態性。

 1     class Mammal
 2     {
 3         public virtual void bark()
 4         {
 5             Console.WriteLine("Mammal.bark()\t 哺乳動物叫聲各不相同");
 6         }
 7 
 8         public void walk()
 9         {
10             Console.WriteLine("Mammal.walk()\t 哺乳動物行走");
11         }
12     }
13 
14     class Dog:Mammal
15     {
16         public override void bark()
17         {
18             Console.WriteLine("Dog.bark()\t 狗的叫聲汪汪汪");
19         }
20 
21         public new void walk()
22         {
23             Console.WriteLine("Dog.walk()\t 狗奔跑很快");
24         }
25     }
26     class Cat:Mammal
27     {
28         public override void bark()
29         {
30             Console.WriteLine("Cat.bark()\t貓的叫聲喵喵喵");
31         }
32 
33         public new void walk()
34         {
35             Console.WriteLine("Cat.walk()\t 貓行動敏捷");
36         }
37     }
38         static void Main(string[] args)
39         {
40             Mammal m;
41             Cat c = new Cat();
42             Dog d = new Dog();
43 
44             Console.WriteLine("調用bark方法");
45             m = c;
46             m.bark();
47             c.bark();
48 
49             m = d;
50             m.bark();
51             d.bark();
52 
53             Console.WriteLine("調用walk方法");
54             m = c;
55             m.walk();
56             c.walk();
57 
58             m = d;
59             m.walk();
60             d.walk();
61 
62 
63             Console.ReadLine();
64         }

  運行結果

調用bark方法
Cat.bark()      貓的叫聲喵喵喵
Cat.bark()      貓的叫聲喵喵喵
Dog.bark()       狗的叫聲汪汪汪
Dog.bark()       狗的叫聲汪汪汪
調用walk方法
Mammal.walk()    哺乳動物行走
Cat.walk()       貓行動敏捷
Mammal.walk()    哺乳動物行走
Dog.walk()       狗奔跑很快()

  由運行結果可以看出用new關鍵字進行方法隱藏後,被調用的方法由變量的定義類型決定。雖然m實際是Dog類(或Cat類)的實例,但是由於m被定義成一個Mammal類型的變量,所以當調用m.walk()方法時,總是調用Mammal類的walk方法,

  而不會調用Cat或Dog類的walk方法。

  對於使用virtual和override關鍵字聲明的方法,再調用時由變量的實際類型決定調用那個類的相應方法。m先後被賦予Cat類型和Dog類型的值,在調用bark方法時,先後調用了Cat類的bark方法和Dog類的bark方法。同一段代碼m.bark,由於變量

  的值不同而表現出不同的行為,形成了多態性。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved