您好,登錄后才能下訂單哦!
眾所周知,C#作為一門OOP(面向對象程序設計)語言,在許多地方都有與C++相似的地方,然而也有很多不同的地方。
說到面向對象,腦袋里第一反應當然就是面向對象的三大原則(java中是四大原則):
封裝、繼承、多態。java中還包括抽象。在此不做過多討論。
今天要討論的虛方法、抽象方法、抽象類、接口所有的一切都是以多態作為基礎的,所以讓我們聚焦多態————
多態是什么?
多態(Polymorphism)按字面的意思就是“多種狀態”。在面向對象語言中,接口的多種不同的實現方式即為多態。引用Charlie Calverts對多態的描述——多態性是允許你將父對象設置成為一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作(摘自“Delphi4編程技術內幕”)。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。多態性在Object Pascal和C++中都是通過虛函數實現的。? (摘自百度百科)
用我自己的理解來說:多態就是在繼承的前提下,不同對象調用相同方法卻表現出不同的行為,此為多態。
關鍵性的一句話:多態性在C++中是通過虛函數實現的,這在C#中同樣適用。但是在C#中有三種方法來體現:虛方法,抽象類,接口。
所謂的虛函數,也就是我們首先要討論的虛方法。
I.虛方法 Virtual
虛方法存在于相對于需要實現多態的子類的父類中,同時也是最基本的實現多態的方法。
具體的語法是在父類中用virtual修飾,然后在子類中使用override進行重寫。以下是一個簡單易懂的例子:貓和狗都是動物,它們都會叫,但是叫聲是不一樣的。
? 1.先定義父類,只定義一個叫做Dosth的方法,代表動物的嚎叫。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsharpTest9_10
{
class Animal
{
public Animal()
{
}
public virtual void Dosth()
{
Console.WriteLine("動物的嚎叫");
}
}
}
? 2.定義貓類:override重寫
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsharpTest9_10
{
class cat:Animal
{
public override void Dosth()
{
base.Dosth();
Console.WriteLine("喵");
}
}
}
3.定義狗類:override重寫
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsharpTest9_10
{
class dog:Animal
{
public override void Dosth()
{
// base.Dosth();
Console.WriteLine("汪");
}
}
}
在主程序中:
cat c1 = new cat();
dog d1 = new dog();
c1.Dosth();
d1.Dosth();
運行結果:
現在反觀結果:我在主程序中調用了貓類重寫的父類方法和狗類重寫的父類方法。唯一的區別是在貓類中重寫方法的時候,在方法體內加入了這樣一句:
base.Dosth();
因此運行結果中同樣輸出了一次父類的方法體中的語句。由此我們可以知道,在子類重寫方法的時候可以使用base.方法名來實現父類原本的函數功能。
在狗類中我屏蔽了這個語句,所以狗類僅僅輸出了自己重寫的方法體。
通過上面的這個例子,算是對多態已經有了最基本的了解。接下來是由虛方法引出的抽象方法以及抽象類。
II.抽象方法以及抽象類 Abstract
? 通過上面的例子我們知道了虛方法。存在于父類中的虛方法是有自己的方法體的,而且這些方法體是必要的,少了他們就無法完成邏輯,這種情況需要使用虛方法。
然而如果父類中的方法完全不知道去干什么(即方法體中沒有必要的代碼),必須要子類進行重寫才有意義的話,這種情況就需要使用抽象方法。
? 抽象方法必須存在于抽象類中,抽象類的具體語法是類名前加上abstract。抽象方法的語法實例如下:public abstract void FUN();
? 仍然使用上面的例子。父類(Animal)中的Dosth方法中,并沒有必要的代碼,即使方法里面什么都不寫對子類仍然沒有什么影響。這種情況就可以使用抽象方法和抽象類。
首先需要注意的是:抽象方法沒有方法體,且所有繼承了抽象類的子類必須重寫所有的抽象方法。
父類:
namespace CsharpTest9_10
{
abstract class Animal
{
public abstract void Dosth();
}
}
子類的代碼不變。但是此時就不能使用base.方法體了,因為根本就不存在方法體。
抽象類中可以包括普通方法,并且抽象類不能被實例化。
抽象類的使用場景:
1.父類方法不知道如何去實現;
2.父類沒有默認實現且不需要實例化
總的來說,抽象方法和虛方法的差別并不是很大,實現的功能都差不多。抽象類保證了每個方法都必須得到重寫,我們就要根據實際需要來選擇對應的方法。
III.接口 Interface
? 同樣的,接口是從抽象類演變而來的————如果抽象類中的所有方法都是抽象方法,這個抽象類就可以叫做接口。當然,接口中的所有方法都不能有方法體。
接口中不能包含字段,但是可以包含屬性。這里沒有字段怎么編寫屬性呢?這里有一個自動屬性的概念,我們將在別的博文中進行講解。
接口中的所有成員都默認為public,這是不能被修改的,自己也不能寫上去。
我們可以將接口想象為一個插件,可以用來實現一些附加功能。
代碼還是使用上一個例子中的那份,首先定義接口:在program中右鍵新建項,選擇接口。
定義如下:
namespace CsharpTest9_10
{
interface Interface1
{
void Eat();
}
}
在貓類中的接口調用:
namespace CsharpTest9_10
{
class cat : Animal,Interface1
{
public override void Dosth()
{
//base.Dosth();
Console.WriteLine("喵");
}
public void Eat()
{
Console.WriteLine("貓在進食");
}
}
}
狗類同理。
我們可以看到調用的語法就是在繼承的父類后加上一個逗號,再寫接口名即可。
此時在接口名上右鍵后點擊實現接口,會自動生成接口中方法的實現。
接口的作用就是實現某些類的特殊功能。
總結
三者之間的關系,我用一張圖來表示。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。