細說C#繼承

来源:https://www.cnblogs.com/green-jcx/archive/2018/08/01/9401608.html
-Advertisement-
Play Games

簡介 繼承(封裝、多態)是面向對象編程三大特性之一,繼承的思想就是擯棄代碼的冗餘,實現更好的重用性。 繼承從字面上理解,無外乎讓人想到某人繼承某人的某些東西,一個給一個拿。這個語義在生活中,就像 家族繼承財產,爺爺將財產繼承給兒女,兒女在將財產繼承給子孫,有些東西可以繼承有些的東西只繼承給 某人。映 ...


簡介

繼承(封裝、多態)是面向對象編程三大特性之一,繼承的思想就是擯棄代碼的冗餘,實現更好的重用性。

繼承從字面上理解,無外乎讓人想到某人繼承某人的某些東西,一個給一個拿。這個語義在生活中,就像

家族繼承財產,爺爺將財產繼承給兒女,兒女在將財產繼承給子孫,有些東西可以繼承有些的東西只繼承給

某人。映射到編程當中,其思想也大致如此。


 通過示例引出繼承的作用

在代碼中定義個三個類:Cat貓、Dog狗、Cattle牛。

從類圖上可以看出紅色標識區域,三個類的定義出現了大量的冗餘(欄位、屬性、方法),那麼在編寫代碼時就會出現大量的重覆代碼。

試想一下,隨著業務功能的擴展,可能會出現更多類,那麼冗餘(重覆的代碼)會更多。比如出現同樣會造成冗餘的類:

Pig豬、Panda熊貓、Sheep羊......等等。這些類同樣會有相同的特征:名稱、性別、年齡、奔跑(欄位、屬性、方法)。


 如何解決此類冗餘問題 —— 使用繼承

繼承的思想:

當我們定義了多個類,這多個類都存在重覆的成員(共性)。我們可以將這些重覆的成員單獨的提取封裝到一個類中,作為這些具有相同特征類的父類。

將此思想作用於上述的三個類

提取共性:可以直觀看出重覆的具有共性的項目有:1.欄位和屬性(年齡、姓名、性別)、2.方法(奔跑)。

封裝到一個類:如何定義這個類?Cat貓、Dog狗、Cattle牛有明顯共同的特性,就是他們都是動物,故可以抽象定義一個Animal動物類。

 

如何在代碼中實現繼承

    class Animal
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private string gender;
        public string Gender
        {
            get { return gender; }
            set { gender = value; }
        }
        
        private int age;
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        
        public void Run()
        {
            Console.WriteLine("奔跑。。。");
        }

    }

    class Cat:Animal
    {   
        public void CatchMouse()
        {
            Console.WriteLine("抓老鼠。。。");
        }
    }

    class Dog:Animal
    {
        public void GuardHouse()
        {
            Console.WriteLine("看家護院。。。");
        }
    }

    class Cattle:Animal
    {
        public void Plowland()
        {
            Console.WriteLine("耕田。。。");
        }
    }

通過一個簡單的  :(冒號)實現了繼承關係。

實現繼承後產生了兩個角色:1.子類(派生類)、2.父類(基類)

代碼中子類刪除父類提取的重覆性成員。

 

實現繼承後的關係如下圖:

實現繼承後每個子類僅保留了自己特有的特性,大大減少了冗餘。

 

繼承後的能力

子類的共性成員都被父類提取了,那麼子類要使用怎麼辦?

子類繼承父類後,將會隱式繼承父類的所有成員,但不包括構造函數。

在繼承後,訪問其父類成員,會受到訪問修飾符的限制。故,修飾為private的私有成員不會訪問到。

 

繼承的特性

1.繼承的單根性:

  一個子類只能有一個父類,就好比一個人只有一個父親。

2.繼承的傳遞性:  

   例如, ClassC 派生自 ClassB,並且 ClassB 派生自 ClassA,則 ClassC 會繼承在 ClassB 和 ClassA 中聲明的成員。

依次順序可以不斷向上取。

圖例:


 繼承被後的秘密 —— 子類和父類的構造函數(難點)

給父類編寫了一個構造函數,示例代碼如下:

 1     class Animal
 2     {
 3         public Animal(string name,string gender,int age)
 4         {
 5             this.Name = name;
 6             this.Gender = gender;
 7             this.Age = age;
 8         }
 9 
10         private string name;
11         public string Name
12         {
13             get { return name; }
14             set { name = value; }
15         }
16 
17         private string gender;
18         public string Gender
19         {
20             get { return gender; }
21             set { gender = value; }
22         }
23         
24         private int age;
25         public int Age
26         {
27             get { return age; }
28             set { age = value; }
29         }
30         
31         public void Run()
32         {
33             Console.WriteLine("奔跑。。。");
34         }
35 
36         private void ri()
37         { }
38 
39     }
40 
41     class Cat:Animal
42     {   
43         public void CatchMouse()
44         {
45             Console.WriteLine("抓老鼠。。。");
46         }
47     }
48 
49     class Dog:Animal
50     {
51         public void GuardHouse()
52         {
53             Console.WriteLine("看家護院。。。");
54         }
55     }
56 
57     class Cattle:Animal
58     {
59         public void Plowland()
60         {
61             Console.WriteLine("耕田。。。");
62         }
63     }

 

嘗試運行:

為什麼會提示報這個錯誤?意思說父類不能沒有一個無參的構造函數。

學過構造函數的應該都會知道,類在沒有指定任何構造函數的情況下,程式預設會指派一個無參的構造函數。

上述的例子由於我們手動添加的那個構造函數,預設的構造函數就被清除掉了。

在暫且不知道原因的情況下,我們嘗試補全那個無參的構造函數,在進行生成代碼,此時編譯通過沒有報錯。

 

根據此特征我們可以推測子類和父類的構造函數一定有關係,但一定不是繼承關係

 

嘗試調用剛剛定義的父類無參構造函數,在調用列表並沒有顯示,只顯示了類自身的一個無參構造函數。

證明瞭子類不能繼承父類的構造函數。

 

通過調試代碼監視子類實例化對象的過程,看它到底和父類的構造函數發生了什麼。

通過調試發現在創建子類對象時的代碼執行邏輯如下:

子類會首先去預設執行父類的無參構造函數,然後在執行自己的構造函數

這條定論就很好的解釋了,為什麼在上述例子為什麼會出現的錯誤。但是子類又為什麼要先去執行父類的構造函數?

解釋:

因為子類繼承了父類的成員,這一項描述只能說明子類擁有的權利,並不代表子類去執行了。

在原則上要使用類的成員,必須要通過類的實例對象去調用。所以子類要調用到父類的成員,就必須去通過調用

父類的構造函數,在子類的內部創建一個父類的對象,以便自己去調用父類的成員。

 

總結:

子類始終要使用父類的一個構造函數在自己內部創建一個父類對象,為了調用父類的成員。

子類預設調用父類的無參構造函數,所以在顯示編寫一個有參構造函數時導致父類沒有了無參構造函數,從而編譯出錯。


 在子類中使用顯示調用父類構造函數

 

作用1:

提高代碼重用性,子類無需在類中定義,直接使用父類的。

作用2:

上述例子講過子類在實例化對象時會調用父類的預設無參構造函數,因為子類的目的就是通過父類構造函數創建一個對象。

通過這樣顯示的調用,那麼在父類有沒有無參構造函數都沒什麼關係了。


子類中存在和父類中相同的成員

示例:

根據VS給我們提示的消息,我們可以看出,當代碼中存在子類的成員和父類的成員相同的時候,子類的成員將父類的成員隱藏了。

隱藏過後子類將無法訪問到父類的成員。如果是刻意為之,我們可以使用new 關鍵字顯示的說明,從而提高可讀性。

指定new關鍵字:

 

此時提示的波浪線已消除。


 其他註意點

在C#中,所有的類都直接或間接的繼承自object類(當我們定義一個類的時候,如果沒有給該類指定繼承一個類,那麼這個類就繼承了object類)。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一:有如下變數(tu是個元祖),請實現要求的功能 tu = ("alex", [11, 22, {"k1": 'v1', "k2": ["age", "name"], "k3": (11,22,33)}, 44]) a. 講述元祖的特性 b. 請問tu變數中的第一個元素 "alex" 是否可被修改? ...
  • 重載與重寫對比: 重載: 許可權修飾符(public private 預設):無關 方法名:重載的兩個方法的方法名必須相同 形參列表: 形參類型的順序不同 形參的個數不同 形參的類型不同 三者至少滿足一個 返回值類型: 重載與返回值類型無關 重寫: 許可權修飾符(public private 預設): ...
  • C 多線程編程系列(二) 線程基礎 [TOC] 1.1 簡介 線程基礎主要包括線程創建、掛起、等待和終止線程。關於更多的線程的底層實現,CPU時間片輪轉等等的知識,可以參考 一書中關於進程和線程的章節,本文不過多贅述。 1.2 創建線程 在C 語言中,創建線程是一件非常簡單的事情;它只需要用到 命名 ...
  • 作為一個獨立開發者產品需要支付介面是挺麻煩的,支付寶微信都不對個人開放,註冊公司維護成本太高,市面上各種收款工具要麼手續費太高,要麼到賬很慢,體驗很不好。 看到 「小叮噹支付」 這個收款工具,挺有意思的。原理是監控手機微信、支付寶的二維碼掃碼支付到賬通知並回調開發者應用,通知開發者用戶的支付結果。 ...
  • 一、前言 上篇實戰完成後,沒想到會有那麼多的圈友給了那麼多的支持,甚至連只是作為代碼倉儲的git上也給了一些小星星,真的感覺很惶恐啊,哈哈哈,畢竟代碼寫的很爛啊。由於上一篇只是大概說了下項目,所以準備寫下這篇詳細說下自己對於獲取當前登錄用戶的設計與實現,原本準備上周末就完成的這篇,結果周六一起來,發 ...
  • 當你選擇電腦或者電子、自控等專業進入大學時,你本來還是有機會從事其它行業的,可你畢業時執迷不悟,仍然選擇了開發做為你的職業,真是自做孽不可活。不過,歡迎你和我一樣加入這個被其它人認為是風光無限的“白領”吧。 如果你不是特別的與人世隔絕,我想你一定看過金老先生的名著《笑傲江湖》吧,裡面有一門十分奇特 ...
  • 字元串: C#中$的用法: 是為了替代string.format();https://www.cnblogs.com/hilolin/p/9123970.htmlhttps://blog.csdn.net/kebi007/article/details/52612610語法糖: C#6.0: htt... ...
  • 概述 OLE,Object Linking and Embedding,即對象連接與嵌入。我們在設計程式時,OLE可以用來創建複合文檔,把文字、聲音、圖像、表格、應用程式等類型的信息組合在一起,在Word中,我們可以通過OLE來實現以上要素信息的組合。下麵的示例中將介紹如何通過C# 來操作Word中 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...