C#快速入門教程(15)—— 繼承
繼承(inherit)是物件導向程式設計中一個非常重要的概念,其主要功能就是對已有程式碼的重複利用,以達到簡化開發、靈活擴充套件的目的。
類的繼承體系中,最基本的概念是繼承與被繼承的關係。我們先來看下面的程式碼。
using System;
namespace ConsoleTest
{
public class Ca
{
public string Name { get; set; }
public void DoWork()
{
Console.WriteLine("Ca.DoWork");
}
}
}
下面,我們定義一個Cb類,它繼承於Ca類,如下面的程式碼。
using System;
namespace ConsoleTest
{
public class Cb : Ca
{
}
}
我們可以看到,Cb類的定義,“Cb : Ca”中的冒號(:)在這裡的含義就是繼承;接下來,我們在Program.cs檔案中測試Cb類的使用,如下面的程式碼。
static void Main(string[] args)
{
Cb b = new Cb();
b.DoWork();
}
程式碼執行結果如下圖所示。
從這個示例中,我們可以看到,Cb類並沒有定義任何成員,但其物件可以呼叫DoWork()方法,而這個方法就是從Ca類中繼承而來的。此時,Ca就是Cb的父類(parent class),也可以稱為超類(super class)或基類(base class);而Cb則是Ca的子類(sub class),它繼承於Ca類。
說到C#中的繼承,我們不提到Object類,它之所以特殊是因為在整個.NET Framework架構中,Object類是唯一一個沒有父類的類,而它也是其他所有型別的最終極父類,當一個類沒有指定父類時,它實際就繼承於Object類。也就是說,在.NET Framework架構中的所有型別都可以使用Object類中的非私有成員,比如GetType()方法、Equals()方法、ToString()方法等,當然,在子類中也可以修改父類成員的實現,從而更適合工作。
實際上,在這裡的Object類、Ca類和Cb的繼承關係就是Cb類繼承於Ca類、Ca類繼承於Object類,這樣,我們就可以在Cb類的物件中呼叫ToString()方法了,如下面的程式碼。
static void Main(string[] args)
{
Cb b = new Cb();
Console.WriteLine(b.ToString());
}
程式碼會顯示b物件的型別,如下圖所示。
實際應用中,如果一個類不允許被繼承,可以在定義是使用sealed關鍵將其“密封”,如下面的程式碼。
public sealed class Ca
在我們在定義Ca類時新增sealed關鍵字後就會出現Cb不能繼承Ca的提示,如下圖所示。
現在,我們已經瞭解了關於繼承的一些基本概念,接下來將討論在使用繼承關係時需要注意的地方。
建構函式
前面的課程,我們已經瞭解瞭如何靈活地建立建構函式,只是在繼承關係中,又多了一些選擇,下面的程式碼,首先在Ca類中建立兩個建構函式,如下面的程式碼。
using System;
namespace ConsoleTest
{
public class Ca
{
// 建構函式
public Ca(string sName)
{
Name = sName;
}
//
public Ca() : this("noname") { }
//
public string Name { get; set; }
public void DoWork()
{
vConsole.WriteLine("Ca.DoWork");
}
}
}
預設情況下,在Cb類中只會繼承Ca類的無引數建構函式,如下面的程式碼。
static void Main(string[] args)
{
Cb b = new Cb();
Console.WriteLine(b.Name);
}
程式碼會顯示noname。但是,如果我們使用Cb b = new Cb("Tom");程式碼建立Cb類的物件就會出現錯誤,如下圖所示。
下面的程式碼,我們通過Ca類中包含一個引數的建構函式來快速建立Cb類中的建構函式。
using System;
namespace ConsoleTest
{
public class Cb : Ca
{
// 建構函式
public Cb(string sName) : base(sName) { }
public Cb() : this("Cb_noname") { }
}
}
這裡,我們通過:符號和base(sName)呼叫了Cb父類(基類),也就是Ca類的單引數建構函式,再次執行Cb b = new Cb("Tom");就沒有問題了。請注意,當新增了任何有引數建構函式後,就不會自動生成無引數的建構函式,如果有需要再次新增,就像上面的程式碼一樣。
這裡,我們使用了base和this關鍵字,大家應注意,this表示當前例項,而base則用於呼叫父類(基類)中的非私有成員。
成員的訪問級別
訪問級別的概念,在前面的課程中已經討論過,具體到類的繼承關係中需要注意的是,定義在父類中的非私有成員,在其子類中可以使用base關鍵字訪問;這裡,父類的非私有成員在大多數情況下是指定義為受保護(protected)或公共(public)的成員。
抽象類及重寫
抽象類不能被例項化,也就是說,我們不能建立抽象類型別的物件。在C#中,定義抽象類時需要使用abstract關鍵字,如下面的程式碼,我們建立了Cx類,它被定義為抽象類。
using System;
namespace ConsoleTest
{
public abstract class Cx
{
public abstract string Name { get; set; }
public abstract void DoWork();
//
public void SayHello()
{
Console.WriteLine("Hello, {0}.", Name);
}
}
}
Cx類中共定義了三個成員,包括抽象屬性Name、抽象方法DoWork()和非抽象方法SayHello()。抽象類是不能建立例項的,所以,程式碼Cx x = new Cx();是不能執行的。
實際應用中,抽象類可以用於定義一系列型別的基本結構,其中可以包含一些共性操作;對於通用的操作可以定義為非抽象成員,如Cx類中的SayHello()方法,一些需要子類具體實現的成員則定義為抽象成員,如Cx類中的DoWork()方法等。需要注意的是,如果類中定義了一個抽象成員,那麼,類就必須定義為抽象類。
下面的程式碼,我們建立兩個Cx類的子類,分別是Cx1類和Cx2類。
//
public class Cx1 : Cx
{
public override string Name { get; set; }
public override void DoWork()
{
Console.WriteLine("Cx1.DoWork()");
}
}
//
public class Cx2 : Cx
{
public override string Name { get; set; }
public override void DoWork()
{
Console.WriteLine("Cx2.DoWork()");
}
}
在重寫抽象成員時,需要使用override關鍵字,如上述程式碼所示。下面的程式碼,我們使用Cx1和Cx2類。
static void Main(string[] args)
{
Cx1 x1 = new Cx1() { Name = "Tom" };
Cx2 x2 = new Cx2() { Name = "Jerry" };
x1.SayHello();
x1.DoWork();
x2.SayHello();
x2.DoWork();
}
程式碼執行結果如下圖所示。
虛擬成員及重寫
在類中定義為虛擬成員時需要使用virtual關鍵字,與抽象成員不同,虛擬成員可以有自己的實現,也可以在子類進行重寫,如下面的程式碼,我們定義Cy類。
using System;
namespace ConsoleTest
{
public class Cy
{
public void DoWork1()
{
Console.WriteLine("Cy.DoWork1");
}
//
public virtual void DoWork2()
{
Console.WriteLine("Cy.DoWork2");
}
}
}
請注意,Cy類中的DoWork2()方法使用了virtual關鍵字,而DoWork1()方法沒有使用virtual關鍵字。下面的程式碼,我們定義Cy類的子類Cy1類。
using System;
namespace ConsoleTest
{
public class Cy1 : Cy
{
new public void DoWork1()
{
Console.WriteLine("Cy1.DoWork1");
}
//
public override void DoWork2()
{
base.DoWork2();
Console.WriteLine("Cy1.DoWork2");
}
}
}
這裡,我們定義的Cy1類作為Cy類的子類,其中包含同名的DoWork1()方法和DoWork2()方法,請注意它們的不同點。
Cy類中的DoWork1()方法定義時沒有使用virtual關鍵字,在其子類Cy1類中,如果需要重寫同名的方法,就應該在方法定義時使用new關鍵字,明確這是一個全新實現的同名成員。
Cy類中的DoWork2()方法定義時使用了virtual關鍵字,在其子類Cy1類中,則可以通過override關鍵字指明是在重寫父類中的方法。
下面的程式碼,我們測試Cy1類的使用。
static void Main(string[] args)
{
Cy1 y1 = new Cy1();
y1.DoWork1();
y1.DoWork2();
}
程式碼執行結果如下圖所示。
CHY軟體小屋原創作品!
相關文章
- C#快速入門教程(30)—— 繼續學習C#
- odoo 開發入門教程系列-繼承(Inheritance)Odoo繼承
- Kotlin學習快速入門(3)——類 繼承 介面Kotlin繼承
- 《C#快速入門教程》目錄C#
- C#快速入門教程(16)—— 介面C#
- C#快速入門教程(6)——方法C#
- Java入門教程九(封裝繼承多型)Java封裝繼承多型
- C#快速入門教程(26)—— 繪圖C#繪圖
- C#快速入門教程(21)—— 泛型C#泛型
- C#快速入門教程(8)——整數C#
- C# 繼承C#繼承
- C#快速入門教程(28)—— ADO.NETC#
- Java入門系列-16-繼承Java繼承
- C#快速入門教程(25)—— 日期與時間C#
- C#快速入門教程(22)—— 常用集合型別C#型別
- C#快速入門教程(18)—— 異常處理C#
- C#快速入門教程(12)—— if語句結構C#
- 子承父業-C#繼承C#繼承
- 瞭解下C# 繼承C#繼承
- C#快速入門教程(27)—— SQL Server資料庫C#SQLServer資料庫
- C#快速入門教程(19)—— 索引器與陣列C#索引陣列
- C#快速入門教程(5)——欄位與屬性C#
- C#快速入門教程(11)—— 字元和字串型別C#字元字串型別
- C#快速入門教程(13)—— switch語句結構C#
- C#快速入門教程(7)——資料型別概述C#資料型別
- C#快速入門教程(2)——程式碼與測試C#
- C++ 整理15_繼承C++繼承
- C#快速入門教程(20)—— 字串與正規表示式C#字串
- C#快速入門教程(23)—— using語句和IDisposable介面C#
- C#快速入門教程(14)—— 迴圈語句結構C#
- C#快速入門教程(4)——類成員的作用域C#
- C#快速入門教程(1)——物件導向程式設計C#物件程式設計
- 如何理解Python中的繼承?python入門Python繼承
- Materialize快速入門教程
- C#快速入門教程(24)—— 路徑、目錄與檔案C#
- C#快速入門教程(17)—— 委託、事件與Lambda表示式C#事件
- C#如何實現多重繼承C#繼承
- C# 12 Blazor入門教程C#Blazor