1. 程式人生 > 其它 >C#易錯易混淆知識總結(七)--{多型}{抽象類於抽象方法}

C#易錯易混淆知識總結(七)--{多型}{抽象類於抽象方法}

一 多型

里氏替換原則就已經說明了多型的精髓“子類物件可以替換父類物件的位置,而程式的功能不受影響”。

      class Person
    {
       
       //定義虛方法以備子類重寫,當子類替換父類物件的位置時,可以表現出多型
        public virtual void Run()
        {
            Console.WriteLine("我是人,我會跑!");
        }

        public virtual void Say()
        {
            Console.WriteLine("
我是人,我會說話!"); } }

//定義Teacher類繼承Person
class Teacher:Person
{
public override void Run()
{
Console.WriteLine("我是老師,我必須慢速跑");
}


public override void Say()
{
Console.WriteLine("我是老師,我得說表揚的話!");
}


}


//定義Student類繼承Person
class Student : Person
{
//子類重寫了父類的虛方法
public override void Run()
{
Console.WriteLine("我是學生,我會加速跑!");
}


public override void Say()
{
Console.WriteLine("我是學生,我會說英語!");
}
}

//實現多型的類
class FeatureHuman
{
/// <summary>
/// 這個方法就提現了多型,當傳入的是子類的物件的時候,p指向的是子類物件,就可以呼叫子類重寫父類方法後的方法
/// </summary>
/// <param name="p">父類或者子類物件</param>
public void OutPutFeature(Person p)
{
p.Run();
p.Say();
}
}

 

主體程式碼和實現多型的方法如下:

static void Main(string[] args)
        {
            FeatureHuman fea = new FeatureHuman();
            //人的特點
            Person p = new Person();

            Program pro = new Program();
            fea.OutPutFeature(p);

            //學生的特點
            Student s = new Student();
            fea.OutPutFeature(s);
            //老師的特點
            Teacher t = new Teacher();
            fea.OutPutFeature(t);

            Console.ReadKey();
        }

執行,列印結果如下:

 

 這裡可以發現,我們outputFeature方法根據傳入的實體物件不同(父類變數指向了子類的物件),而打印出了不同人物的特點,這就是多型。

多型總結如下:

 

 二,抽象類和抽象方法

在C#中使用abstract關鍵字修飾的類和方法,叫做抽象類和抽象方法。

1)抽象類中可以擁有沒抽象成員,為了繼承給他的子類呼叫 (抽象類就是為了定義抽象成員,繼承給子類去實現,同時子類也可以呼叫父類的非抽象成員)

abstract  class Person
    {
       //private int nAge;

       //abstract string strName;

       //抽象類可以包含不抽象的成員,可以給繼承的子類使用
       public void Say()
       {
           Console.WriteLine("我是父類,我是人!");
       }

       public virtual void Sing()
       {
           Console.WriteLine("我是父類,我是人,我可以唱歌!");
       }

       //Run的抽象方法
       public abstract void Run();
    }

2)抽象類中可以有virtual修飾的虛方法

如上面的程式碼,在抽象類中定義了virtual修飾的方法,編譯通過。抽象類就是為了定義抽象成員,繼承給子類去實現,所以子類也可以實現抽象類中的虛方法。

3)抽象類不能例項化,因為有抽象成員,而抽象成員沒有方法體,如下圖,

4)抽象成員不能私有,如果私有子類沒有辦法訪問 

我們可以在抽象類中定義私有成員,但是沒有意義。因為子類根本訪問不到這些私有成員,而抽象類本身也不能例項化,所以私有成員訪問不到。

5)子類必須重寫父類的抽象方法 

在上面程式碼的基礎上,我們定義一個Student類,繼承抽象類,但是不實現抽象類的抽象方法,編譯報錯。程式碼如下:

 6)在子類中沒有辦法通過base關鍵字呼叫父類抽象方法 

原理同上,抽象類的抽象發放沒有實現語句,就算呼叫也沒有意義。但是可以使用base關鍵字呼叫非抽象方法,程式碼如下:

class Program
    {
        static void Main(string[] args)
        {
            //Person p = new Person();
            Student s = new Student();
            s.Run();
            Console.ReadLine();
        }
    }

    class Student : Person
    {
       
        public override void Run()
        { 
            base.Say();
            Console.WriteLine("我是學生,繼承了父類,我可以跑!");
        }
    }

總結如下:

 

抽象方法:

1)抽象方法必須定義在抽象類中,

2)抽象方法必須使用關鍵字修飾,示例程式碼如下:

abstract class Person
    {
        //private int nAge;

        //abstract string strName;

        //抽象類可以包含不抽象的成員,可以給繼承的子類使用
        public void Say()
        {
            Console.WriteLine("我是父類,我是人!");
        }

        public virtual void Sing()
        {
            Console.WriteLine("我是父類,我是人,我可以唱歌!");
        }

        //Run的抽象方法,不能有方法體,留給子類實現
        public abstract void Run();

 

那麼什麼時候使用抽象類呢?

①子類必須重寫父類的方法(相當於定義了一個標準,規範)

②父類沒有必要例項化,就用抽象類

③抽象類是為了繼承,為了多型