1. 程式人生 > 實用技巧 >面向物件程式設計(第2天):多型性和繼承(繼承)

面向物件程式設計(第2天):多型性和繼承(繼承)

介紹 在本文的第一部分中,我們瞭解了方法過載的不同場景,並做了很多有趣的操作。在本系列的第2部分,我的文章將只關注OOP中的繼承概念。讓我們用一些要點來定義繼承: 路線圖 我們仍然堅持在開始學習OOP系列之前定義的路線圖: 潛水在OOP(第一天):多型和繼承(早期繫結/編譯時多型)潛水在OOP(第二天):多型和繼承(繼承)潛水OOP(第三天):多型和繼承(動態繫結/執行時多型)潛水在OOP(第四天):多型和繼承(關於Abstarct類在c#中)潛水在OOP(第五天):都是用c#訪問修飾符(公共/私人/保護/內部/密封/常量/只讀的欄位)潛水OOP(6天):理解列舉在c#中(一個實際的方法)深入OOP(第七天):用c#屬性(一個實際的方法)深入OOP(8天):用c#索引器(一個實際的方法)潛水印銻OOP(9天):瞭解c#事件(Insight)學習c#(第十天):代表在c#中(一個實際的方法)學習c#(11天):c#事件(一個實際的方法) 繼承在行動 好的。讓我們動手做一下。建立一個控制檯應用程式並將其命名為InheritanceAndPolymorphism。新增一個名為ClassA的類和一個名為ClassB的類,程式碼如下: 注意:每一個程式碼片段寫本文是嘗試和測試。 隱藏,複製Code

ClassA:

   class ClassA
     {
        
     }

ClassB:

    class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

我們看到類ClassA是空的,於是我們在類ClassB中添加了兩個方法,即Display1和Display2。我們還有一個變數x宣告並定義為值100。 現在在主程式的方法。cs,寫以下程式碼: Program.cs 隱藏,複製Code

class Program
  {
      static void Main(string[] args)
      {

          ClassA a = new ClassA();
          a.Display1();
      }
  }

如果我們執行程式碼,會立即導致編譯時錯誤。 錯誤:“InheritanceAndPolymorphism。ClassA'不包含'Display1'的定義,也沒有擴充套件方法'Display1'接受型別'InheritanceAndPolymorphism的第一個引數。可以找到ClassA'(您是否丟失了using指令或彙編引用?) 也就是說,很明顯,我們在ClassA中沒有Display1方法的定義,我們也不能使用ClassA例項訪問同一個方法,因為它不是派生自任何像ClassB這樣包含Display1方法的類。類ClassA不包含任何已定義的程式碼或變數。空類不會丟擲任何錯誤,因為我們可以例項化一個看起來像(ClassA的例項)的物件。出現這個錯誤是因為類ClassA沒有名為Display1的方法。但是類ClassB有一個名為Display1的方法。如果允許我們從ClassA本身訪問classB的所有程式碼,那該有多有趣。 使用:運算子從ClassB派生類ClassA,程式碼如下: 隱藏,複製Code

ClassA:

  class ClassA:ClassB
    {
        
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

Program.cs 隱藏,複製Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

現在按原樣執行程式碼,我們得到一個輸出。 輸出 隱藏,複製Code

ClassB Display1

也就是說,現在ClassA可以訪問ClassB繼承的公共方法。錯誤消失,並呼叫ClassB中的Display1。如果在類的名稱後面指定:,另一個類的名稱,很多變化同時發生。a類現在據說是從b類派生出來的。這意味著我們在ClassB中編寫的所有程式碼現在都可以在ClassA中訪問和使用。如果我們真的寫了所有包含在ClassA中的ClassB中的程式碼。如果我們建立了一個類似於ClassB的例項,它能做的一切,現在ClassA的例項也能做。但是我們還沒有在ClassA中寫一行程式碼。我們相信ClassA有一個變數x和兩個函式Display1和Display2,因為ClassB包含這兩個函式。因此,我們進入了繼承的概念,其中ClassB是基類,ClassA是派生類。 讓我們看另一種情況。假設我們遇到這樣一種情況,ClassA也有一個與ClassB中的方法同名的方法。讓我們也在ClassA中定義一個方法Derive1,這樣我們的ClassA程式碼就變成: 隱藏,複製Code

class ClassA:ClassB
    {
        public void Display1()
        {
            System.Console.WriteLine("ClassA Display1");
        }
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

現在,如果我們執行應用程式使用以下程式碼片段為Program.cs類: 隱藏,複製Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

問題是現在會發生什麼?輸出是什麼?是否有任何輸出或編譯錯誤。好,我們來執行一下。 我們得到的輸出: 隱藏,複製Code

ClassA Display1

但是你注意到一件事了嗎,我們在執行程式碼時也收到了一個警告: 警告:' inheritanceandpolymorphism . class . display1()'隱藏了被繼承的成員' inheritanceandpolymorphism . class . display1()'。如果需要隱藏,請使用new關鍵字。 請記住:沒有人可以阻止派生類擁有在其基類中已經聲明瞭相同名稱的方法。 因此,ClassA無疑可以包含Display1方法,它在ClassB中已經用相同的名稱定義了。 當我們呼叫a.Display1(), c#首先檢查類ClassA是否有一個名為Display1的方法。如果沒有找到,就檢入基類。早期的Display1方法僅在基類ClassB中可用,因此被執行。這裡,因為它在ClassA中,它從ClassA而不是ClassB中被呼叫。 請記住:派生類首先執行,然後是基類。 這樣做的原因是基類可能有許多方法,由於各種原因,我們可能對它們的功能不滿意。我們應該有完全的權利擁有要呼叫的方法的副本。換句話說,派生類方法覆蓋基類中定義的方法。 如果我們在派生類中使用base關鍵字呼叫基類Display1方法會發生什麼?,因此我們的ClassA程式碼為: 隱藏,複製Code

ClassA:

  class ClassA:ClassB
    {
        public void Display1()
        {
            Console.WriteLine("ClassA Display1");
            base.Display1();
        }
    }

ClassB:

class ClassB
    {
        public int x = 100;
        public void Display1()
        {
            Console.WriteLine("ClassB Display1");
        }
        public void Display2()
        {
            Console.WriteLine("ClassB Display2");
        }
    }

Program.cs 隱藏,複製Code

class Program
    {
        static void Main(string[] args)
        {
            ClassA a = new ClassA();
            a.Display1();
            Console.ReadKey();
        }
    }

輸出 隱藏,複製Code

ClassA Display1 
ClassB Display1

我們在這裡看到,ClassA Display1方法被呼叫,然後ClassB Display1方法被呼叫。 現在,如果您想要兩個類中最好的,您可能想要先呼叫基類(ClassB) Display1,然後呼叫您的,反之亦然。為了實現這一點,c#提供了一個免費的關鍵字,稱為base。關鍵字基可以在任何派生類中使用。它意味著從基類中呼叫該方法。因此基地。Display1將從類b呼叫方法Display1,也就是前面定義的類a的基類。 更多文章,請接觸實際的方法。 注意:可以在派生類中使用一個名為“base”的保留關鍵字來呼叫基類方法。 如果我們用派生類ClassA的例項從基類呼叫Display2方法會怎樣? 隱藏,收縮,複製Code

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
 {
     public int x = 100;
     public void Display1()
     {
         Console.WriteLine("ClassB Display1");
     }
     public void Display2()
     {
         Console.WriteLine("ClassB Display2");
     }
 }

 /// <summary>
 /// ClassA: acting as derived class
 /// </summary>
 class ClassA : ClassB
 {
     public void Display1()
     {
         Console.WriteLine("ClassA Display1");
         base.Display2();
     }
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 class Program
 {
     static void Main(string[] args)
     {
         ClassA a = new ClassA();
         a.Display1();
         Console.ReadKey();
     }
 }

輸出 隱藏,複製Code

ClassA Display1
ClassB Display2

在上面的程式碼中,我們只做了一個很小的更改,base。Display1被base.Display2取代。在這個特定的場景中,呼叫類ClassB中的方法Display2。Base通常是一個非常通用的用途。它允許我們從派生類訪問基類的成員,如前面解釋的那樣。我們不能在ClassB中使用base,因為根據我們的程式碼,ClassB不是派生自任何類。這樣就完成了base關鍵字只能在派生類中使用? 讓我們看另一個例子: 隱藏,收縮,複製Code

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
 {
     public int x = 100;
     public void Display1()
     {
         Console.WriteLine("ClassB Display1");
     }
 }

 /// <summary>
 /// ClassA: acting as derived class
 /// </summary>
 class ClassA : ClassB
 {
     public void Display2()
     {
         Console.WriteLine("ClassA Display2");
     }
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 class Program
 {
     static void Main(string[] args)
     {
         ClassB b = new ClassB();
         b.Display2();
         Console.ReadKey();
     }
 }

輸出 錯誤:“InheritanceAndPolymorphism。ClassB'不包含'Display2'的定義,也沒有擴充套件方法'Display2'接受型別'InheritanceAndPolymorphism的第一個引數。可以找到ClassB'(您是否丟失了using指令或彙編引用?) 請記住:繼承不是向後工作的。 所以我們得到了一個錯誤。因為我們看到,ClassA是從ClassB派生出來的。, ClassB是基類。因此,類ClassA可以使用類ClassB的所有成員。繼承沒有向後相容性,無論ClassA包含什麼成員都不會向上滲透到ClassB。當我們試圖從類ClassB的例項中訪問類a的Display2方法時,它不能將其提供給類ClassB,從而出現錯誤。 注意:除了建構函式和解構函式外,類從基類繼承了所有東西。 如果類ClassC從類ClassB派生,而類b又從類ClassA派生,那麼類c將繼承在類b和類a中宣告的所有成員。這在繼承中稱為傳遞概念。派生類可以繼承基類的所有成員,但不能從基類中刪除成員。然而,派生類可以通過建立同名方法來隱藏基類的成員。基類的原始成員/方法不會被修改,也不受派生類中發生的任何事情的影響。它在基類中保持不變。,只是在派生類中不可見。 類成員可以是兩種型別,即直接屬於類的靜態成員,或者通過類的例項訪問且只屬於該特定例項的例項成員。例項成員只能通過類的物件訪問,不能直接由類訪問。類中宣告的預設成員是非靜態的,我們只需通過使用static關鍵字使其為靜態的。 所有類都派生自一個名為object的公共基類。所以Object是所有類的母體。 如果我們不從任何其他類派生任何類,則c#負責將:object本身新增到類定義中。物件是唯一不從任何其他類派生的類。它是所有類的最終基類。 假設類a是從類b派生的,就像在我們的例子中一樣,但是類b不是從任何類派生的, 隱藏,複製Code

public class ClassB
 {
 }

 public class ClassA : ClassB
 {
 }

c#自動新增:object到ClassB,即,程式碼在編譯時變為: 隱藏,複製Code

public class ClassB:object
{
}

public class ClassA : ClassB
{
}

但根據理論,我們說ClassB是ClassA的直接基類,所以ClassA的類是ClassB和object。 勒t的去另一個例子: 隱藏,複製Code

public class ClassW : System.ValueType
  {
  }

  public class ClassX : System.Enum
  {
  }

  public class ClassY : System.Delegate
  {
  }

  public class ClassZ : System.Array
  {
  }

我們有四個類定義,每個來自一個建於類在c#中,讓我們執行程式碼。 我們得到很多編譯時錯誤。 錯誤 隱藏,複製Code

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'
'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'
'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'
'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'

不要害怕。 你注意到這個詞的特殊類。定義我們的類不能繼承特殊類在c#中建成的。 記住:在繼承在c#中,定製類不能來自特殊的c#類像系統建成的。ValueType、系統。列舉系統。委託,系統。陣列等。 一個例子, 隱藏,複製Code

public class ClassW
  {
  }

  public class ClassX
  {
  }

  public class ClassY : ClassW, ClassX
  {
  }

在上述例子中,我們看到三個類,ClassW, ClassX和優雅。優雅來自ClassW ClassX。現在如果我們執行程式碼,我們得到了什麼? 編譯時錯誤:InheritanceAndPolymorphism類”。優雅的InheritanceAndPolymorphism不能有多個基類:。ClassW’和‘ClassX”。 所以要記住一點:一個類只能來自一個類在c#中。c#不支援多重繼承的類。 *多重繼承在c#中可以通過使用介面來完成,我們不是本文討論的介面。 我們不允許來自不止一個類,每個類只能有一個基類。 另一個例子: 假設我們試著寫程式碼如下: 隱藏,複製Code

public class ClassW:ClassY
 {
 }

 public class ClassX:ClassW
 {
 }

 public class ClassY :  ClassX
 {
 }

程式碼非常可讀的和簡單的,ClassW來源於優雅,ClassX源自ClassW,優雅又來源於ClassX。所以沒有多重繼承的問題,我們的程式碼應該建立成功。讓我們編譯程式碼。我們得到了什麼?又一個編譯時錯誤。 錯誤:圓形基類涉及“InheritanceAndPolymorphism的依賴。ClassX’和‘InheritanceAndPolymorphism.ClassW”。 記住:是不允許迴圈依賴繼承在c#中。ClassX來源於ClassW來源於優雅,優雅又來源於ClassX,造成迴圈依賴三個類,在邏輯上是不可能的。 均衡的例項/物件 讓我們直接從一個真實的案例: 隱藏,複製Code

ClassB:
public class ClassB
    {
        public int b = 100;
    }

ClassA:

    public class ClassA
    {
        public int a = 100;
    }

Program.cs 隱藏,複製Code

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
    private static void Main(string[] args)
    {
        ClassB classB = new ClassB();
        ClassA classA = new ClassA();
        classA = classB;
        classB = classA;
    }
}

我們在這裡試圖將兩個物件或兩個不同的類的兩個例項。讓我們編譯程式碼, 我們得到編譯時錯誤: 錯誤 隱藏,複製Code

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

InheritanceAndPolymorphism是我用於控制檯應用程式的名稱空間,所以不需要害怕這個詞,只是忽略它。 c#工作規則,它將永遠不會讓你把不同的相互獨立的類的物件。因此,我們不能把一個物件classA classA classB classB反之亦然。不管類包含相似的結構和它們的變數初始化類似的整數值,即使我們做的。 隱藏,複製Code

public class ClassB
 {
     public int a = 100;
 }

 public class ClassA
 {
     public int a = 100;
 }

我只是改變了int b ClassB int。在這種情況下,將一個物件是不允許的,不可能的。 c#也非常特殊,如果它有處理的資料型別。 但是有一個方法。通過這種方式,我們將討論其中的一個錯誤將會消失。唯一一次我們可以將不同的資料型別是隻有當我們來自他們嗎?看看下面提到的程式碼。中詳細討論這一點,當我們建立一個物件的ClassB宣佈新的,我們建立兩個物件,一個看起來像ClassB,另一個看起來像物件,即。來源於物件類(即最終基類)。所有類在c#中最終來源於物件。自ClassA來自ClassB我們宣佈新的ClassA,我們建立三個物件,一個看起來像ClassB,一個看起來像ClassA和最後看起來像物件類。 隱藏,複製Code

public class ClassB
 {
     public int b = 100;
 }

 public class ClassA:ClassB
 {
     public int a = 100;
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 public class Program
 {
     private static void Main(string[] args)
     {
         ClassB classB = new ClassB();
         ClassA classA = new ClassA();
         classA = classB;
         classB = classA;
     }
 }

我們只是ClassA來自ClassB,這是我們能做的,在本文中我們學到了很多關於這個。現在編譯程式碼,我們得到: 錯誤:不能隱式型別轉換的InheritanceAndPolymorphism。ClassB”到“InheritanceAndPolymorphism.ClassA”。存在一個顯式轉換(你失蹤一嗎?) 就像我提到的,c#非常講究物件等同。 因此,當我們寫classA = classB classA看起來像classA例項,classB物件和classB看起來像classB,在ClassB.Result有比賽嗎?沒有錯誤:-)。儘管classB和classA有相同的值,使用classB我們只能訪問classB的成員,即使我們使用classA classA也可以訪問。我們有貶值classB的效力。這個錯誤發生在classA = classB。類ClassA ClassB和更多。我們不能有右邊的基類和派生類在左邊。classB只代表一個classB而classA預計classA classA和classB。 要記住一點:,我們可以將一個物件的基類派生類而不是反之亦然。 另一個程式碼片段: 隱藏,複製Code

public class ClassB
    {
        public int b = 100;
    }

    public class ClassA:ClassB
    {
        public int a = 100;
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA();
            classB=classA;
            classA = (ClassA)classB;
        }
    }

雖然我們違反了c#的情商在使用物件時,我們沒有得到任何編譯器錯誤,因為我們對物件進行了轉換。()稱為cast。在方括號中,類的名稱是put。一個演員陣容基本上是一個偉大的平等。當我們打算寫classA = classB時,c#期望等號的右邊是一個classA,即。,一個ClassA例項。但是它找到了classB,即。,一個ClassB例項。當我們應用轉換時,我們試著將ClassB的例項轉換為ClassA的例項。這種方法滿足c#關於只等同於相似物件型別的規則。記住,只有在這一行的持續時間裡,classB才會變成ClassA而不是classB。 現在,如果我們將ClassB作為基類移除到class ClassA,就像下面的程式碼那樣,並嘗試將ClassA轉換為ClassB物件。 隱藏,複製Code

public class ClassB
 {
     public int b = 100;
 }

 public class ClassA // Removed ClassB as base class
 {
     public int a = 100;
 }

 /// <summary>
 /// Program: used to execute the method.
 /// Contains Main method.
 /// </summary>
 public class Program
 {
     private static void Main(string[] args)
     {
         ClassB classB = new ClassB();
         ClassA classA = new ClassA();
         classB = (ClassB)classA;
         classA = (ClassA)classB;
     }
 }

輸出 錯誤 隱藏,複製Code

Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'
Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'    

*'InheritanceAndPolymorphism ':我在我的應用中使用的名稱空間,所以忽略它。 因此,我們看到,只有當這兩個類中的一個是從另一個派生的時候,型別轉換才有效。我們不能相互轉換任何兩個物件。 最後一個例子: 隱藏,複製Code

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
    private static void Main(string[] args)
    {
        int integerA = 10;
        char characterB = 'A';
        integerA = characterB;
        characterB = integerA;
    }
}

我們執行程式碼。 輸出 錯誤:不能隱式地將型別'int'轉換為'char'。存在顯式轉換(是否缺少強制轉換?) 注意:我們不能隱式地將整型轉換為char型,但是char型可以轉換為int型。 結論 在本系列文章的這一部分中,我們學習了繼承。為了深入理解這一概念,我們採用了各種場景和實際示例。在下一篇文章中,我們將討論執行時多型。繼承在執行時多型中扮演著非常重要的角色。 讓我們列出所有需要記住的要點: 沒有人可以阻止派生類擁有在其基類中已經聲明瞭相同名稱的方法。派生類第一次有機會執行,然後是基類。可以在派生類中使用一個名為“base”的保留關鍵字來呼叫基類方法。繼承不會向後工作。除了建構函式和解構函式外,類從基類繼承一切。在c#的繼承中,自定義類不能從特殊的內建c#類派生,比如System。ValueType、系統。列舉系統。委託,系統。陣列等。在c#中,類只能從一個類派生。c#不支援通過類的方式進行多重繼承。迴圈依賴在c#繼承中是不允許的。ClassX從ClassW派生而來,ClassW又從ClassY派生而來,ClassY又從ClassX派生而來,這導致了三個類之間的迴圈依賴,這在邏輯上是不可能的。我們可以將基類的物件等同於派生類,但反之則不行。我們不能隱式地將整型轉換為char型,但是char型可以轉換為int型。 在本系列的第一篇文章中,您可以閱讀關於編譯時多型性的內容。堅持編碼和學習。 我的其他系列文章: MVC: http://www.codeproject.com/Articles/620195/Learning-MVC-Part-Introduction-to-MVC-Architectu RESTful webapi: http://www.codeproject.com/Articles/990492/RESTful-Day-sharp-Enterprise-Level-Application 編碼快樂! 本文轉載於:http://www.diyabc.com/frontweb/news2108.html