c#基礎知識梳理(四)

上期回顧 -?https://www.cnblogs.com/liu-jinxin/p/10826971.html?

一、類

  當你定義一個類時,你定義了一個數據類型的藍圖。這實際上并沒有定義任何的數據,但它定義了類的名稱意味著什么,也就是說,類的對象由什么組成及在這個對象上可執行什么操作。對象是類的實例。構成類的方法和變量成為類的成員。

  代碼示例:

 1 using System;
 2 namespace BoxApplication
 3 {
 4     class Box
 5     {
 6        public double length;   // 長度
 7        public double breadth;  // 寬度
 8        public double height;   // 高度
 9     }
10     class Boxtester
11     {
12         static void Main(string[] args)
13         {
14             Box Box1 = new Box();        // 聲明 Box1,類型為 Box
15             Box Box2 = new Box();        // 聲明 Box2,類型為 Box
16             double volume = 0.0;         // 體積
17 
18             // Box1 詳述
19             Box1.height = 5.0;
20             Box1.length = 6.0;
21             Box1.breadth = 7.0;
22 
23             // Box2 詳述
24             Box2.height = 10.0;
25             Box2.length = 12.0;
26             Box2.breadth = 13.0;
27            
28             // Box1 的體積
29             volume = Box1.height * Box1.length * Box1.breadth;
30             Console.WriteLine("Box1 的體積: {0}",  volume);
31 
32             // Box2 的體積
33             volume = Box2.height * Box2.length * Box2.breadth;
34             Console.WriteLine("Box2 的體積: {0}", volume);
35             Console.ReadKey();
36         }
37     }
38 }
39 //執行結果
40 //Box1 的體積: 210
41 //Box2 的體積: 1560
View Code

  (一)、成員函數

    類的成員函數是一個在類定義中有它的定義或原型的函數,就像其他變量一樣。作為類的一個成員,它能在類的任何對象上操作,且能訪問該對象的類的所有成員。

    成員變量是對象的屬性(從設計角度),且它們保持私有來實現封裝。這些變量只能使用公共成員函數來訪問。

    代碼示例:

 1 using System;
 2 namespace BoxApplication
 3 {
 4     class Box
 5     {
 6        private double length;   // 長度
 7        private double breadth;  // 寬度
 8        private double height;   // 高度
 9        public void setLength( double len )
10        {
11             length = len;
12        }
13 
14        public void setBreadth( double bre )
15        {
16             breadth = bre;
17        }
18 
19        public void setHeight( double hei )
20        {
21             height = hei;
22        }
23        public double getVolume()
24        {
25            return length * breadth * height;
26        }
27     }
28     class Boxtester
29     {
30         static void Main(string[] args)
31         {
32             Box Box1 = new Box();        // 聲明 Box1,類型為 Box
33             Box Box2 = new Box();                // 聲明 Box2,類型為 Box
34             double volume;                               // 體積
35 
36 
37             // Box1 詳述
38             Box1.setLength(6.0);
39             Box1.setBreadth(7.0);
40             Box1.setHeight(5.0);
41 
42             // Box2 詳述
43             Box2.setLength(12.0);
44             Box2.setBreadth(13.0);
45             Box2.setHeight(10.0);
46        
47             // Box1 的體積
48             volume = Box1.getVolume();
49             Console.WriteLine("Box1 的體積: {0}" ,volume);
50 
51             // Box2 的體積
52             volume = Box2.getVolume();
53             Console.WriteLine("Box2 的體積: {0}", volume);
54            
55             Console.ReadKey();
56         }
57     }
58 }
59 //執行結果
60 //Box1 的體積: 210
61 //Box2 的體積: 1560
View Code

  (二)、構造函數

    類的?構造函數?是類的一個特殊的成員函數,當創建類的新對象時執行

    構造函數的名稱與類的名稱完全相同,它沒有任何返回類型。

    代碼示例:

 1 using System;
 2 namespace LineApplication
 3 {
 4    class Line
 5    {
 6       private double length;   // 線條的長度
 7       public Line()    //構造函數
 8       {
 9          Console.WriteLine("對象已創建");
10       }
11 
12       public void setLength( double len )
13       {
14          length = len;
15       }
16       public double getLength()
17       {
18          return length;
19       }
20 
21       static void Main(string[] args)
22       {
23          Line line = new Line();    
24          // 設置線條長度
25          line.setLength(6.0);
26          Console.WriteLine("線條的長度: {0}", line.getLength());
27          Console.ReadKey();
28       }
29    }
30 }
31 //執行結果:
32 //對象已創建
33 //線條的長度: 6
View Code

    默認的構造函數沒有任何參數。但是如果你需要一個帶有參數的構造函數可以有參數,這種構造函數叫做參數化構造函數。這種技術可以幫助你在創建對象的同時給對象賦初始值

   代碼示例:

 1 using System;
 2 namespace LineApplication
 3 {
 4    class Line
 5    {
 6       private double length;   // 線條的長度
 7       public Line(double len)  // 參數化構造函數
 8       {
 9          Console.WriteLine("對象已創建,length = {0}", len);
10          length = len;
11       }
12 
13       public void setLength( double len )
14       {
15          length = len;
16       }
17       public double getLength()
18       {
19          return length;
20       }
21 
22       static void Main(string[] args)
23       {
24          Line line = new Line(10.0);
25          Console.WriteLine("線條的長度: {0}", line.getLength()); 
26          // 設置線條長度
27          line.setLength(6.0);
28          Console.WriteLine("線條的長度: {0}", line.getLength()); 
29          Console.ReadKey();
30       }
31    }
32 }
33 //執行結果:
34 //對象已創建,length = 10
35 //線條的長度: 10
36 //線條的長度: 6
View Code

  (三)、析構函數

    類的?析構函數?是類的一個特殊的成員函數,當類的對象超出范圍時執行。

    析構函數的名稱是在類的名稱前加上一個波浪形(~)作為前綴,它不返回值,也不帶任何參數。

    析構函數用于在結束程序(比如關閉文件、釋放內存等)之前釋放資源。析構函數不能繼承或重載。

    代碼示例:

 1 using System;
 2 namespace LineApplication
 3 {
 4    class Line
 5    {
 6       private double length;   // 線條的長度
 7       public Line()  // 構造函數
 8       {
 9          Console.WriteLine("對象已創建");
10       }
11       ~Line() //析構函數
12       {
13          Console.WriteLine("對象已刪除");
14       }
15 
16       public void setLength( double len )
17       {
18          length = len;
19       }
20       public double getLength()
21       {
22          return length;
23       }
24 
25       static void Main(string[] args)
26       {
27          Line line = new Line();
28          // 設置線條長度
29          line.setLength(6.0);
30          Console.WriteLine("線條的長度: {0}", line.getLength());           
31       }
32    }
33 }
34 //執行結果:
35 //對象已創建
36 //線條的長度: 6
37 //對象已刪除
View Code

    構造函數在創建實例時調用,析構函數在結束程序時調用。

  (四)、靜態成員

    我們可以使用?static?關鍵字把類成員定義為靜態的。當我們聲明一個類成員為靜態時,意味著無論有多少個類的對象被創建,只會有一個該靜態成員的副本。

    關鍵字?static?意味著類中只有一個該成員的實例。靜態變量用于定義常量,因為它們的值可以通過直接調用類而不需要創建類的實例來獲取。靜態變量可在成員函數或類的定義外部進行初始化。你也可以在類的定義內部初始化靜態變量。

    代碼示例:

 1 using System;
 2 namespace StaticVarApplication
 3 {
 4     class StaticVar
 5     {
 6        public static int num;
 7         public void count()
 8         {
 9             num++;
10         }
11         public int getNum()
12         {
13             return num;
14         }
15     }
16     class StaticTester
17     {
18         static void Main(string[] args)
19         {
20             StaticVar s1 = new StaticVar();
21             StaticVar s2 = new StaticVar();
22             s1.count();
23             s1.count();
24             s1.count();
25             s2.count();
26             s2.count();
27             s2.count();         
28             Console.WriteLine("s1 的變量 num: {0}", s1.getNum());
29             Console.WriteLine("s2 的變量 num: {0}", s2.getNum());
30             Console.ReadKey();
31         }
32     }
33 }
34 //執行結果
35 //s1 的變量 num: 6
36 //s2 的變量 num: 6
View Code

    你也可以把一個成員函數聲明為?static。這樣的函數只能訪問靜態變量。靜態函數在對象被創建之前就已經存在。

    代碼示例:

 1 using System;
 2 namespace StaticVarApplication
 3 {
 4     class StaticVar
 5     {
 6        public static int num;
 7         public void count()
 8         {
 9             num++;
10         }
11         public static int getNum()
12         {
13             return num;
14         }
15     }
16     class StaticTester
17     {
18         static void Main(string[] args)
19         {
20             StaticVar s = new StaticVar();
21             s.count();
22             s.count();
23             s.count();                   
24             Console.WriteLine("變量 num: {0}", StaticVar.getNum());
25             Console.ReadKey();
26         }
27     }
28 }
29 //執行結果:
30 //變量 num: 3
View Code

    將類成員函數聲明為public static無需實例化即可調用類成員函數。

    反之,如果不聲明為static,即使和Main方法從屬于同一個類,也必須經過實例化

    代碼示例:

 1 //示例一:
 2 using System;
 3 
 4 namespace ConsoleApp
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             int num = AddClass.Add(2, 3);  //編譯通過
11             Console.WriteLine(num);
12         }
13     }
14 
15     class AddClass
16     {
17         public static int Add(int x,int y)
18         {
19             return x + y;
20         }
21     }
22 }
23 
24 //示例二:
25 using System;
26 
27 namespace ConsoleApp
28 {
29     class Program
30     {
31         static void Main(string[] args)
32         {
33             int num = Add(2, 3);  //編譯錯誤,即使改為Program.Add(2, 3);也無法通過編譯
34             Console.WriteLine(num);
35         }
36 
37         public int Add(int x, int y)
38         {
39             return x + y;
40         }
41     }
42 }
43 using System;
44 
45 namespace ConsoleApp
46 {
47     class Program
48     {
49         static void Main(string[] args)
50         {
51             Program self = new Program();
52             int num = self.Add(2, 3);  //編譯通過
53             Console.WriteLine(num);
54         }
55 
56         public int Add(int x, int y)
57         {
58             return x + y;
59         }
60     }
61 }
View Code

    注:

      我們可以使用?static?關鍵字把類成員定義為靜態的。當我們聲明一個類成員為靜態時,意味著無論有多少個類的對象被創建,只會有一個該靜態成員的副本。

      關鍵字?static?意味著類中只有一個該成員的實例。靜態變量用于定義常量,因為它們的值可以通過直接調用類而不需要創建類的實例來獲取。靜態變量可在成員函數或類的定義外部進行初始化。你也可以在類的定義內部初始化靜態變量。

二、封裝

  封裝是面向對象程序設計中最重要的概念之一。封裝?被定義為"把一個或多個項目封閉在一個物理的或者邏輯的包中"。在面向對象程序設計方法論中,封裝是為了防止對實現細節的訪問。

  抽象和封裝是面向對象程序設計的相關特性。抽象允許相關信息可視化,封裝則使開發者實現所需級別的抽象

  C# 封裝根據具體的需要,設置使用者的訪問權限,并通過?訪問修飾符?來實現。

  一個?訪問修飾符?定義了一個類成員的范圍和可見性。C# 支持的訪問修飾符如下所示:

    1、public:所有對象都可以訪問;

    2、private:對象本身在對象內部可以訪問;

    3、protected:只有該類對象及其子類對象可以訪問

    4、internal:同一個程序集的對象可以訪問;

    5、protected internal:訪問限于當前程序集或派生自包含類的類型。

   (一)、public

      Public 訪問修飾符允許一個類將其成員變量和成員函數暴露給其他的函數和對象。任何公有成員可以被外部的類訪問。

      代碼示例:

 1 using System;
 2 namespace RectangleApplication
 3 {
 4     class Rectangle
 5     {
 6         //成員變量
 7         public double length;
 8         public double width;
 9 
10         public double GetArea()
11         {
12             return length * width;
13         }
14         public void Display()
15         {
16             Console.WriteLine("長度: {0}", length);
17             Console.WriteLine("寬度: {0}", width);
18             Console.WriteLine("面積: {0}", GetArea());
19         }
20     }// Rectangle 結束
21 
22     class ExecuteRectangle
23     {
24         static void Main(string[] args)
25         {
26             Rectangle r = new Rectangle();
27             r.length = 4.5;
28             r.width = 3.5;
29             r.Display();
30             Console.ReadLine();
31         }
32     }
33 }
34 //執行結果:
35 //長度: 4.5
36 //寬度: 3.5
37 //面積: 15.75
View Code

   (二)、private

     Private 訪問修飾符允許一個類將其成員變量和成員函數對其他的函數和對象進行隱藏。只有同一個類中的函數可以訪問它的私有成員。即使是類的實例也不能訪問它的私有成員

     代碼示例:

 1 using System;
 2 namespace RectangleApplication
 3 {
 4     class Rectangle
 5     {
 6         //成員變量
 7         private double length;
 8         private double width;
 9 
10         public void Acceptdetails()
11         {
12             Console.WriteLine("請輸入長度:");
13             length = Convert.ToDouble(Console.ReadLine());
14             Console.WriteLine("請輸入寬度:");
15             width = Convert.ToDouble(Console.ReadLine());
16         }
17         public double GetArea()
18         {
19             return length * width;
20         }
21         public void Display()
22         {
23             Console.WriteLine("長度: {0}", length);
24             Console.WriteLine("寬度: {0}", width);
25             Console.WriteLine("面積: {0}", GetArea());
26         }
27     }//end class Rectangle    
28     class ExecuteRectangle
29     {
30         static void Main(string[] args)
31         {
32             Rectangle r = new Rectangle();
33             r.Acceptdetails();
34             r.Display();
35             Console.ReadLine();
36         }
37     }
38 }
39 //執行結果:
40 //請輸入長度:
41 //4.4
42 //請輸入寬度:
43 //3.3
44 //長度: 4.4
45 //寬度: 3.3
46 //面積: 14.52
View Code

   (三)、protected

     Protected 訪問修飾符允許子類訪問它的基類的成員變量和成員函數。這樣有助于實現繼承。我們將在繼承的章節詳細討論這個。更詳細地討論這個。

   (四)、internal

     Internal 訪問說明符允許一個類將其成員變量和成員函數暴露給當前程序中的其他函數和對象。換句話說,帶有 internal 訪問修飾符的任何成員可以被定義在該成員所定義的應用程序內的任何類或方法訪問。

     代碼示例:

 1 using System;
 2 
 3 namespace RectangleApplication
 4 {
 5     class Rectangle
 6     {
 7         //成員變量
 8         internal double length;
 9         internal double width;
10         
11         double GetArea()
12         {
13             return length * width;
14         }
15        public void Display()
16         {
17             Console.WriteLine("長度: {0}", length);
18             Console.WriteLine("寬度: {0}", width);
19             Console.WriteLine("面積: {0}", GetArea());
20         }
21     }//end class Rectangle    
22     class ExecuteRectangle
23     {
24         static void Main(string[] args)
25         {
26             Rectangle r = new Rectangle();
27             r.length = 4.5;
28             r.width = 3.5;
29             r.Display();
30             Console.ReadLine();
31         }
32     }
33 }
34 //執行結果:
35 //長度: 4.5
36 //寬度: 3.5
37 //面積: 15.75
View Code

   (五)、protected internal

     Protected Internal 訪問修飾符允許在本類,派生類或者包含該類的程序集中訪問。這也被用于實現繼承。

    注:

      • ?Pubilc?:任何公有成員可以被外部的類訪問。
      • ?Private?:只有同一個類中的函數可以訪問它的私有成員。
      • ?Protected?:該類內部和繼承類中可以訪問。
      • ?internal?: 同一個程序集的對象可以訪問。
      • ?Protected internal?:3 和 4 的并集,符合任意一條都可以訪問。

      1、范圍比較:private < internal/protected < protected internal < public

      2、public 和 internal 修飾符的區別:

      一個是國際妓女,誰用都可以,就是 public,一個是不懂外語的,只能在國內做生意,就是 internal,只能在當前所在的工程里面引用。你建兩個工程,建立一個引用關系,被引用的里面建兩個類,就能區別了。用 VS 的話,你根本點不出來那個不懂外語的。

三、繼承

  繼承是面向對象程序設計中最重要的概念之一。繼承允許我們根據一個類來定義另一個類,這使得創建和維護應用程序變得更容易。同時也有利于重用代碼和節省開發時間。

當創建一個類時,程序員不需要完全重新編寫新的數據成員和成員函數,只需要設計一個新的類,繼承了已有的類的成員即可。這個已有的類被稱為的基類,這個新的類被稱為派生類

  繼承的思想實現了?屬于(IS-A)?關系。例如,哺乳動物?屬于(IS-A)?動物,狗?屬于(IS-A)?哺乳動物,因此狗?屬于(IS-A)?動物。

  基類與派生類:一個類可以派生自多個類或接口,這意味著它可以從多個基類或接口繼承數據和函數。 - 父類與子類

  (一)、基類的初始化

    派生類繼承了基類的成員變量和成員方法。因此父類對象應在子類對象創建之前被創建。您可以在成員初始化列表中進行父類的初始化。

    代碼示例:

 1 using System;
 2 namespace RectangleApplication
 3 {
 4    class Rectangle
 5    {
 6       // 成員變量
 7       protected double length;
 8       protected double width;
 9       public Rectangle(double l, double w)
10       {
11          length = l;
12          width = w;
13       }
14       public double GetArea()
15       {
16          return length * width;
17       }
18       public void Display()
19       {
20          Console.WriteLine("長度: {0}", length);
21          Console.WriteLine("寬度: {0}", width);
22          Console.WriteLine("面積: {0}", GetArea());
23       }
24    }//end class Rectangle  
25    class Tabletop : Rectangle
26    {
27       private double cost;
28       public Tabletop(double l, double w) : base(l, w)
29       { }
30       public double GetCost()
31       {
32          double cost;
33          cost = GetArea() * 70;
34          return cost;
35       }
36       public void Display()
37       {
38          base.Display();
39          Console.WriteLine("成本: {0}", GetCost());
40       }
41    }
42    class ExecuteRectangle
43    {
44       static void Main(string[] args)
45       {
46          Tabletop t = new Tabletop(4.5, 7.5);
47          t.Display();
48          Console.ReadLine();
49       }
50    }
51 }
52 //執行結果
53 //長度: 4.5
54 //寬度: 7.5
55 //面積: 33.75
56 //成本: 2362.5
View Code

  (二)、多重繼承

    多重繼承指的是一個類別可以同時從多于一個父類繼承行為與特征的功能。與單一繼承相對,單一繼承指一個類別只可以繼承自一個父類。

    C# 不支持多重繼承。但是,您可以使用接口來實現多重繼承。

    代碼示例:

 1 using System;
 2 namespace InheritanceApplication
 3 {
 4    class Shape 
 5    {
 6       public void setWidth(int w)
 7       {
 8          width = w;
 9       }
10       public void setHeight(int h)
11       {
12          height = h;
13       }
14       protected int width;
15       protected int height;
16    }
17 
18    // 基類 PaintCost
19    public interface PaintCost 
20    {
21       int getCost(int area);
22 
23    }
24    // 派生類
25    class Rectangle : Shape, PaintCost
26    {
27       public int getArea()
28       {
29          return (width * height);
30       }
31       public int getCost(int area)
32       {
33          return area * 70;
34       }
35    }
36    class RectangleTester
37    {
38       static void Main(string[] args)
39       {
40          Rectangle Rect = new Rectangle();
41          int area;
42          Rect.setWidth(5);
43          Rect.setHeight(7);
44          area = Rect.getArea();
45          // 打印對象的面積
46          Console.WriteLine("總面積: {0}",  Rect.getArea());
47          Console.WriteLine("油漆總成本: ${0}" , Rect.getCost(area));
48          Console.ReadKey();
49       }
50    }
51 }
52 //執行結果:
53 //總面積: 35
54 //油漆總成本: $2450
View Code

    注:

    為什么一個對象可以用父類聲明,卻用子類實例化?

     這個實例是子類的,但是因為你聲明時是用父類聲明的,所以你用正常的辦法訪問不到子類自己的成員,只能訪問到從父類繼承來的成員。

     在子類中用 override 重寫父類中用 virtual 申明的虛方法時,實例化父類調用該方法,執行時調用的是子類中重寫的方法;

     如果子類中用 new 覆蓋父類中用 virtual 申明的虛方法時,實例化父類調用該方法,執行時調用的是父類中的虛方法;

 1 /// <summary>  
 2 /// 父類  
 3 /// </summary>  
 4 public class ParentClass  
 5 {  
 6    public virtual void ParVirMethod()  
 7    {  
 8        Console.WriteLine("父類的方法...");  
 9    }  
10 }  
11 
12 /// <summary>  
13 /// 子類1  
14 /// </summary>  
15 public class ChildClass1 : ParentClass  
16 {  
17    public override void ParVirMethod()  
18    {  
19        Console.WriteLine("子類1的方法...");  
20    }  
21 }  
22 
23 /// <summary>  
24 /// 子類2  
25 /// </summary>  
26 public class ChildClass2 : ParentClass  
27 {  
28    public new void ParVirMethod()  
29    {  
30        Console.WriteLine("子類2的方法...");  
31    }  
32 
33    public void Test()  
34    {  
35        Console.WriteLine("子類2的其他方法...");  
36    }  
37 }  
38 
39 //執行調用:
40 ParentClass par = new ChildClass1();  
41 par.ParVirMethod(); //結果:"子類1的方法",調用子類的方法,實現了多態
42 
43 par = new ChildClass2();  
44 par.ParVirMethod(); //結果:"父類的方法",調用父類的方法,沒有實現多態  
View Code

     深究其原因,為何兩者不同,是因為原理不同:?override是重寫,即將基類的方法在派生類里直接抹去重新寫,故而調用的方法就是子類方法;而new只是將基類的方法在派生類里隱藏起來,故而調用的仍舊是基類方法。

     應用舉例:

     有這樣的需要,比如 People 類有一個 Run 方法,Man 和 Woman 這兩個類都是繼承自 People 的類,并且都重寫(override)了 Run 這個方法(男人女人跑起步來不一樣)。

     現在有一群人一起跑步,有男人有女人。

     我們可以把這些都裝進一個People數組(假設為peoples)。

     然后:

       foreach(People p in peoples) // peoples中對象不同(即有男有女),用于實例化的子類就不同。        {        p.Run(); // 故而,調用的方法也不同,實現了多態        }

     由于多態性,在調用 p.Run() 的時候 p 對象本身如果是男人就會自動調用男人的 Run 方法,是女人就會調用女人的 Run 方法。

     依賴倒置原則

       依賴倒置原則,DIP,Dependency Inverse Principle DIP的表述是:

       1、高層模塊不應該依賴于低層模塊, 二者都應該依賴于抽象。

       2、抽象不應該依賴于細節,細節應該依賴于抽象。

       這里說的“依賴”是使用的意思,如果你調用了一個類的一個方法,就是依賴這個類,如果你直接調用這個類的方法,就是依賴細節,細節就是具體的類,但如果你調用的是它父類或者接口的方法,就是依賴抽象, 所以 DIP 說白了就是不要直接使用具體的子類,而是用它的父類的引用去調用子類的方法,這樣就是依賴于抽象,不依賴具體。

       其實簡單的說,DIP 的好處就是解除耦合,用了 DIP 之后,調用者就不知道被調用的代碼是什么,因為調用者拿到的是父類的引用,它不知道具體指向哪個子類的實例,更不知道要調用的方法具體是什么,所以,被調用代碼被偷偷換成另一個子類之后,調用者不需要做任何修改, 這就是解耦了。

四、多態

  多態性意味著有多重形式。在面向對象編程范式中,多態性往往表現為"一個接口,多個功能"。

  多態性可以是靜態的或動態的。在靜態多態性中,函數的響應是在編譯時發生的。在動態多態性中,函數的響應是在運行時發生的。

  (一)、靜態多態性

    在編譯時,函數和對象的連接機制被稱為早期綁定,也被稱為靜態綁定。C# 提供了兩種技術來實現靜態多態性。分別為:

      • 函數重載
      • 運算符重載

    運算符重載將在下一章節討論,接下來我們將討論函數重載。

  (二)、函數重載

    您可以在同一個范圍內對相同的函數名有多個定義。函數的定義必須彼此不同,可以是參數列表中的參數類型不同,也可以是參數個數不同。不能重載只有返回類型不同的函數聲明。下面的實例演示了幾個相同的函數?print(),用于打印不同的數據類型:

    代碼示例:

 1 using System;
 2 namespace PolymorphismApplication
 3 {
 4    class Printdata
 5    {
 6       void print(int i)
 7       {
 8          Console.WriteLine("Printing int: {0}", i );
 9       }
10 
11       void print(double f)
12       {
13          Console.WriteLine("Printing float: {0}" , f);
14       }
15 
16       void print(string s)
17       {
18          Console.WriteLine("Printing string: {0}", s);
19       }
20       static void Main(string[] args)
21       {
22          Printdata p = new Printdata();
23          // 調用 print 來打印整數
24          p.print(5);
25          // 調用 print 來打印浮點數
26          p.print(500.263);
27          // 調用 print 來打印字符串
28          p.print("Hello C++");
29          Console.ReadKey();
30       }
31    }
32 }
33 //執行結果:
34 //Printing int: 5
35 //Printing float: 500.263
36 //Printing string: Hello C++
View Code

  (三)、動態多態性

    C# 允許您使用關鍵字?abstract?創建抽象類,用于提供接口的部分類的實現。當一個派生類繼承自該抽象類時,實現即完成。抽象類包含抽象方法,抽象方法可被派生類實現。派生類具有更專業的功能。

    請注意,下面是有關抽象類的一些規則:

      • 您不能創建一個抽象類的實例。
      • 您不能在一個抽象類外部聲明一個抽象方法。
      • 通過在類定義前面放置關鍵字?sealed,可以將類聲明為密封類。當一個類被聲明為?sealed?時,它不能被繼承。抽象類不能被聲明為 sealed。

    代碼示例:

 1 using System;
 2 namespace PolymorphismApplication
 3 {
 4    abstract class Shape
 5    {
 6        abstract public int area();
 7    }
 8    class Rectangle:  Shape
 9    {
10       private int length;
11       private int width;
12       public Rectangle( int a=0, int b=0)
13       {
14          length = a;
15          width = b;
16       }
17       public override int area ()
18       { 
19          Console.WriteLine("Rectangle 類的面積:");
20          return (width * length); 
21       }
22    }
23 
24    class RectangleTester
25    {
26       static void Main(string[] args)
27       {
28          Rectangle r = new Rectangle(10, 7);
29          double a = r.area();
30          Console.WriteLine("面積: {0}",a);
31          Console.ReadKey();
32       }
33    }
34 }
35 //執行結果:
36 //Rectangle 類的面積:
37 //面積: 70
View Code

    當有一個定義在類中的函數需要在繼承類中實現時,可以使用虛方法。虛方法是使用關鍵字?virtual?聲明的。虛方法可以在不同的繼承類中有不同的實現。對虛方法的調用是在運行時發生的。

    動態多態性是通過?抽象類?和?虛方法?實現的。

    代碼示例:

 1 using System;
 2 namespace PolymorphismApplication
 3 {
 4    class Shape 
 5    {
 6       protected int width, height;
 7       public Shape( int a=0, int b=0)
 8       {
 9          width = a;
10          height = b;
11       }
12       public virtual int area()
13       {
14          Console.WriteLine("父類的面積:");
15          return 0;
16       }
17    }
18    class Rectangle: Shape
19    {
20       public Rectangle( int a=0, int b=0): base(a, b)
21       {
22 
23       }
24       public override int area ()
25       {
26          Console.WriteLine("Rectangle 類的面積:");
27          return (width * height); 
28       }
29    }
30    class Triangle: Shape
31    {
32       public Triangle(int a = 0, int b = 0): base(a, b)
33       {
34       
35       }
36       public override int area()
37       {
38          Console.WriteLine("Triangle 類的面積:");
39          return (width * height / 2); 
40       }
41    }
42    class Caller
43    {
44       public void CallArea(Shape sh)
45       {
46          int a;
47          a = sh.area();
48          Console.WriteLine("面積: {0}", a);
49       }
50    }  
51    class Tester
52    {
53       
54       static void Main(string[] args)
55       {
56          Caller c = new Caller();
57          Rectangle r = new Rectangle(10, 7);
58          Triangle t = new Triangle(10, 5);
59          c.CallArea(r);
60          c.CallArea(t);
61          Console.ReadKey();
62       }
63    }
64 }
65 //執行結果:
66 //Rectangle 類的面積:
67 //面積:70
68 //Triangle 類的面積:
69 //面積:25
View Code

    注:

    1、virtual和abstract都是用來修飾父類的,通過覆蓋父類的定義,讓子類重新定義。

      • virtual修飾的方法必須有實現(哪怕是僅僅添加一對大括號),而abstract修飾的方法一定不能實現。
      • virtual可以被子類重寫,而abstract必須被子類重寫。
      • 如果類成員被abstract修飾,則該類前必須添加abstract,因為只有抽象類才可以有抽象方法。
      • 無法創建abstract類的實例,只能被繼承無法實例化。

      2、overload和override

        重載(overload)是提供了一種機制, 相同函數名通過不同的返回值類型以及參數來表來區分的機制。

        重寫(override)是用于重寫基類的虛方法,這樣在派生類中提供一個新的方法。

      3、抽象方法和虛方法

      • 虛方法必須有實現部分,抽象方法沒有提供實現部分,抽象方法是一種強制派生類覆蓋的方法,否則派生類將不能被實例化。
      • ?抽象方法只能在抽象類中聲明,虛方法不是。如果類包含抽象方法,那么該類也是抽象的,也必須聲明類是抽象的。
      • ?抽象方法必須在派生類中重寫,這一點和接口類似,虛方法不需要再派生類中重寫。

      簡單說,抽象方法是需要子類去實現的。虛方法是已經實現了的,可以被子類覆蓋,也可以不覆蓋,取決于需求。抽象方法和虛方法都可以供派生類重寫。

    對于面向對象的特性,推薦幾篇不錯的文章:

      https://www.cnblogs.com/harrogath/p/6445793.html

      https://www.cnblogs.com/autumn001/p/9036148.html

?五、下期預告-敬請期待

  ->運算符重載

  ->接口

  ->命名空間

  ->預處理器指令

  ->正則表達式

  ->異常處理

  ->文件的輸入輸出

  參考文獻:https://www.runoob.com/csharp/csharp-encapsulation.html

?根據w3school自我溫習一下c#基礎,分享給大家。

轉載于:https://www.cnblogs.com/liu-jinxin/p/10831189.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247949.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247949.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247949.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UIButton設置圓角和邊框及邊框顏色

UIButton *testButton [UIButton buttonWithType:UIButtonTypeSystem];[testButton setFrame:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 100,100)];[testButton setTitle:"獲取屏幕尺寸" forState:UIControlStateNormal];[testButt…

Git 的介紹簡介

使用 git 管理我們的項目并上傳到碼云 ##1. 本地管理 本地工作區 git add >暫存區 git commit > 倉庫區 git status : 查看我們的狀態 查看到很多紅色的 (有修改的 有刪除的 有添加的) git add . : 把當前所有文件添加到暫存區 git commit -m xxx 把代碼從暫存區 提交…

【王俊杰de人工智能實戰課】第7次作業2

Brief Guide 項目內容這個作業屬于哪個課程北航人工智能實戰課這個作業的要求在哪里第三次作業要求我在這個課程的目標是獲得機器學習相關的完整項目與學習經驗&#xff1b;通過與人工智能行業的大牛們聊天了解行業不同方向的發展以便進行職業規劃&#xff1b;為轉CS積累基礎知…

讓UITableView的section header view不懸停的方法

當 UITableView 的 style 屬性設置為 Plain 時&#xff0c;這個tableview的section header在滾動時會默認懸停在界面頂端。取消這一特性的方法有兩種&#xff1a; 將 style 設置為 Grouped 。這時所有的section header都會隨著scrollview滾動了。不過 grouped 和 plain 的樣式…

Promise 的基本使用 與 Ajax的jQuery封裝

Promise 的基本使用 為了解決回調地獄問題&#xff0c;從而給出的解決辦法&#xff1a; /*** Promise** 1. Promise 是 一個構造函數 new Vue()* 2. Promise() 里面有個參數, 參數就是一個回調 () > {}* 回調也有參數* resolve f 操作成功的時候調用resolve > …

個人沖刺9

1.昨天做了界面整體優化。 2.今天打算了解一下組成員的情況。 3.整體界面優化沒有什么問題。轉載于:https://www.cnblogs.com/Evak/p/10936840.html

iOS UITextField使用全攻略

//初始化textfield并設置位置及大小 UITextField *text [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 130, 30)]; //設置邊框樣式&#xff0c;只有設置了才會顯示邊框樣式 text.borderStyle UITextBorderStyleRoundedRect; typedef enum { UITextBorderStyleNone…

日期模糊查詢

SELECT * FROM 表名 t WHERE(to_char(t.日期字段,yyyy-MM-dd hh24:mi:ss)like %2011%)轉載于:https://www.cnblogs.com/macT/p/10865206.html

Uboot中start.S源碼的指令級的詳盡解析(轉)

Uboot中start.S源碼的指令級的詳盡解析轉載于:https://www.cnblogs.com/LittleTiger/p/10877516.html

Vuex說明及Todos項目改造

Vuex(vue) / Flux (angular) /Redux(react) vuex 是什么? 狀態管理工具 狀態即數據, 狀態管理就是管理組件中的data數據 Vuex 中的狀態管理工具,采用了 集中式 方式統一管理項目中組件之間需要通訊的數據 [看圖] 如何使用 最佳實踐 : 只將組件之間共享的數據放在 vuex …

Objective-C 深復制和淺復制與NSCopying協議

1.簡單復制只能實現淺拷貝&#xff1a;指針賦值&#xff0c;使兩個指針指向相同的一塊內存空間&#xff0c;操作不安全。 2. Foundation類已經遵守了<NSCopying>和 <NSMutableCopying>協議,即實現了copy和mutableCopy方法,因此Foundation對象可以使用這些方法創建對…

基于Vue項目打包上線配置

打包上線 開發階段 : npm run serve發布階段 : npm run build build之前 1. 把基準地址, 由開發階段的換成發布階段的 //main.js axios.defaults.baseURL http://localhost:30002. 忽略項目中打印的結果 // main.js console.log () > {}// 開發階段 > 注釋掉 >…

NSTimer 進階使用總結與注意事項

NSTimer 是 iOS 上的一種計時器&#xff0c;通過 NSTimer 對象&#xff0c;可以指定時間間隔&#xff0c;向一個對象發送消息。NSTimer 是比較常用的工具&#xff0c;比如用來定時更新界面&#xff0c;定時發送請求等等。但是在使用過程中&#xff0c;有很多需要注意的地方&…

一步一步教你實現iOS音頻頻譜動畫(一)

如果你想先看看最終效果再決定看不看文章 -> bilibili示例代碼下載 第二篇&#xff1a;一步一步教你實現iOS音頻頻譜動畫&#xff08;二&#xff09; 基于篇幅考慮&#xff0c;本次教程分為兩篇文章&#xff0c;本篇文章主要講述音頻播放和頻譜數據的獲取&#xff0c;下篇將…

微信小程序的基礎 (一)

微信小程序介紹- 鏈接 微信小程序&#xff0c;簡稱小程序&#xff0c;是一種不需要下載安裝即可使用的應用&#xff0c;它實現了應用“觸手可及”的夢想&#xff0c;用戶掃一掃或搜一下即可打開應用 1. 為什么是微信小程序? 微信有海量用戶&#xff0c;而且粘性很高&#x…

看YYModel源碼的一些收獲

關于源碼學習自己的一些感悟第一層&#xff1a;熟練使用&#xff1b;第二層&#xff1a;讀懂代碼&#xff1b;第三層&#xff1a;通曉原理&#xff1b;第四層&#xff1a;如何設計&#xff1b;自己學到了什么&#xff0c;還留有什么問題&#xff1b;關于分享關于線下演講分享和…

IDEA提交項目到SVN

一.提交步驟 VCS--Enable...-->點擊項目右鍵-->subversion-->share directory-->commit 二.IDEA SVN 忽略文件的設置 1》share .使用idea在將項目提交到svn的過程中遇到這樣的問題 將項目share之后再設置ignore files &#xff0c;在commit的時候&#xff0c;不會將…

小程序基礎 (二)

小程序開發框架 小程序開發框架的目標是通過盡可能簡單、高效的方式讓開發者可以在微信中開發具有原生 APP 體驗的服務。 整個小程序框架系統分為兩部分&#xff1a;邏輯層&#xff08;App Service&#xff09;和 視圖層&#xff08;View&#xff09;。 小程序提供了自己的視…

項目ITP(五) spring4.0 整合 Quartz 實現任務調度

版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主同意不得轉載。https://blog.csdn.net/u010378410/article/details/26016025 2014-05-16 22:51 by Jeff Li 前言 系列文章&#xff1a;[傳送門] 項目需求&#xff1a; 二維碼推送到一體機上&#xff0c;給學生簽到掃…

喜歡用Block的值得注意-Block的Retain Cycle的解決方法

本文不講block如何聲明及使用&#xff0c;只講block在使用過程中暫時遇到及帶來的隱性危險。 主要基于兩點進行演示&#xff1a; 1.block 的循環引用(retain cycle) 2.去除block產生的告警時&#xff0c;需注意問題。 有一次&#xff0c;朋友問我當一個對象中的block塊中的訪問…