眾所周知,C#作為一門OOP(面向?qū)ο蟪绦蛟O(shè)計)語言,在許多地方都有與C++相似的地方,然而也有很多不同的地方。
我們提供的服務(wù)有:網(wǎng)站設(shè)計、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、正安ssl等。為上1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的正安網(wǎng)站制作公司
說到面向?qū)ο?,腦袋里第一反應(yīng)當(dāng)然就是面向?qū)ο蟮娜笤瓌t(java中是四大原則):
封裝、繼承、多態(tài)。java中還包括抽象。在此不做過多討論。
今天要討論的虛方法、抽象方法、抽象類、接口所有的一切都是以多態(tài)作為基礎(chǔ)的,所以讓我們聚焦多態(tài)————
多態(tài)是什么?
多態(tài)(Polymorphism)按字面的意思就是“多種狀態(tài)”。在面向?qū)ο笳Z言中,接口的多種不同的實現(xiàn)方式即為多態(tài)。引用Charlie Calverts對多態(tài)的描述——多態(tài)性是允許你將父對象設(shè)置成為一個或更多的他的子對象相等的技術(shù),賦值之后,父對象就可以根據(jù)當(dāng)前賦值給它的子對象的特性以不同的方式運作(摘自“Delphi4編程技術(shù)內(nèi)幕”)。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。多態(tài)性在Object Pascal和C++中都是通過虛函數(shù)實現(xiàn)的。? (摘自百度百科)
用我自己的理解來說:多態(tài)就是在繼承的前提下,不同對象調(diào)用相同方法卻表現(xiàn)出不同的行為,此為多態(tài)。
關(guān)鍵性的一句話:多態(tài)性在C++中是通過虛函數(shù)實現(xiàn)的,這在C#中同樣適用。但是在C#中有三種方法來體現(xiàn):虛方法,抽象類,接口。
所謂的虛函數(shù),也就是我們首先要討論的虛方法。
I.虛方法 Virtual
虛方法存在于相對于需要實現(xiàn)多態(tài)的子類的父類中,同時也是最基本的實現(xiàn)多態(tài)的方法。
具體的語法是在父類中用virtual修飾,然后在子類中使用override進(jìn)行重寫。以下是一個簡單易懂的例子:貓和狗都是動物,它們都會叫,但是叫聲是不一樣的。
? 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();
運行結(jié)果:
現(xiàn)在反觀結(jié)果:我在主程序中調(diào)用了貓類重寫的父類方法和狗類重寫的父類方法。唯一的區(qū)別是在貓類中重寫方法的時候,在方法體內(nèi)加入了這樣一句:
base.Dosth();
因此運行結(jié)果中同樣輸出了一次父類的方法體中的語句。由此我們可以知道,在子類重寫方法的時候可以使用base.方法名來實現(xiàn)父類原本的函數(shù)功能。
在狗類中我屏蔽了這個語句,所以狗類僅僅輸出了自己重寫的方法體。
通過上面的這個例子,算是對多態(tài)已經(jīng)有了最基本的了解。接下來是由虛方法引出的抽象方法以及抽象類。
II.抽象方法以及抽象類 Abstract
? 通過上面的例子我們知道了虛方法。存在于父類中的虛方法是有自己的方法體的,而且這些方法體是必要的,少了他們就無法完成邏輯,這種情況需要使用虛方法。
然而如果父類中的方法完全不知道去干什么(即方法體中沒有必要的代碼),必須要子類進(jìn)行重寫才有意義的話,這種情況就需要使用抽象方法。
? 抽象方法必須存在于抽象類中,抽象類的具體語法是類名前加上abstract。抽象方法的語法實例如下:public abstract void FUN();
? 仍然使用上面的例子。父類(Animal)中的Dosth方法中,并沒有必要的代碼,即使方法里面什么都不寫對子類仍然沒有什么影響。這種情況就可以使用抽象方法和抽象類。
首先需要注意的是:抽象方法沒有方法體,且所有繼承了抽象類的子類必須重寫所有的抽象方法。
父類:
namespace CsharpTest9_10
{
abstract class Animal
{
public abstract void Dosth();
}
}
子類的代碼不變。但是此時就不能使用base.方法體了,因為根本就不存在方法體。
抽象類中可以包括普通方法,并且抽象類不能被實例化。
抽象類的使用場景:
1.父類方法不知道如何去實現(xiàn);
2.父類沒有默認(rèn)實現(xiàn)且不需要實例化
總的來說,抽象方法和虛方法的差別并不是很大,實現(xiàn)的功能都差不多。抽象類保證了每個方法都必須得到重寫,我們就要根據(jù)實際需要來選擇對應(yīng)的方法。
III.接口 Interface
? 同樣的,接口是從抽象類演變而來的————如果抽象類中的所有方法都是抽象方法,這個抽象類就可以叫做接口。當(dāng)然,接口中的所有方法都不能有方法體。
接口中不能包含字段,但是可以包含屬性。這里沒有字段怎么編寫屬性呢?這里有一個自動屬性的概念,我們將在別的博文中進(jìn)行講解。
接口中的所有成員都默認(rèn)為public,這是不能被修改的,自己也不能寫上去。
我們可以將接口想象為一個插件,可以用來實現(xiàn)一些附加功能。
代碼還是使用上一個例子中的那份,首先定義接口:在program中右鍵新建項,選擇接口。
定義如下:
namespace CsharpTest9_10
{
interface Interface1
{
void Eat();
}
}
在貓類中的接口調(diào)用:
namespace CsharpTest9_10
{
class cat : Animal,Interface1
{
public override void Dosth()
{
//base.Dosth();
Console.WriteLine("喵");
}
public void Eat()
{
Console.WriteLine("貓在進(jìn)食");
}
}
}
狗類同理。
我們可以看到調(diào)用的語法就是在繼承的父類后加上一個逗號,再寫接口名即可。
此時在接口名上右鍵后點擊實現(xiàn)接口,會自動生成接口中方法的實現(xiàn)。
接口的作用就是實現(xiàn)某些類的特殊功能。
總結(jié)
三者之間的關(guān)系,我用一張圖來表示。