1. 程式人生 > >面向對象三大特性: 多態

面向對象三大特性: 多態

virtual prot 子類 public 圖片 設計 out 不同的 多態性

什麽是多態:

父類的一些成員,子類繼承周去重寫從而實現不同的功能。

多態的風雷

多態分為兩種,一種是編譯時的多態,一種是運行時的多態。

編譯時多態:編譯時的多態性是通過重載來實現的。

編譯時的多態性:編譯時的多態性是通過重載來實現的。對於非虛的成員來說,系統在編譯時,根據傳遞的參數、返回的類型等信息決定實現何種操作。

運行時的多態性:運行時的多態性就是指直到系統運行時,才根據實際情況決定實現何種操作。C#中運行時的多態性是通過覆寫虛成員實現。

多態的實現

重載(overload)

重載指的是同一個累中有兩個或者多個名字但是參數不同的方法。

public void Calculate()
{
    
// do the calculation here } public void Calculate(int num) { // do the calculation here }

運行時多態: 重寫

重寫有兩種, 一種是override修飾符, 另一種使用new 修飾符

重新(override)是對父類中的虛函數(virtual method)或抽象函數的“覆蓋”。

/// <summary>
    /// 動物類(父類)
    /// </summary>
    class Animal
    {
       /// <summary>
       /// 名字
       
/// 說明:類和子類可訪問 /// </summary> protected string name; /// <summary> /// 構造函數 /// </summary> /// <param name="name"></param> public Animal(string name) { this.name=name; } /// <summary> /// 名字(虛屬性)
/// </summary> public virtual string MyName { get { return this.name; } } /// <summary> /// 吃(虛方法) /// </summary> public virtual void Eat() { Console.WriteLine("我會吃!"); } /// <summary> /// 叫(虛方法) /// </summary> public virtual void Shout() { Console.WriteLine("我會叫!"); } } /// <summary> /// 狗(子類) /// </summary> class Dog:Animal { string myName; public Dog(string name): base(name) { myName = name; } /// <summary> /// 名字(重寫父類屬性) /// </summary> public override string MyName { get { return "我是:狗狗,我叫:"+this.name; } } /// <summary> /// 吃(重寫父類虛方法) /// </summary> public override void Eat() { Console.WriteLine("我喜歡吃肉!"); } /// <summary> /// 叫(重寫父類方法) /// </summary> public override void Shout() { Console.WriteLine("汪!汪!汪!"); } } /// <summary> /// 貓(子類) /// </summary> class Cat : Animal { string myName; public Cat(string name) : base(name) { myName = name; } /// <summary> /// 名字(重寫父類屬性) /// </summary> public override string MyName { get { return "我是:貓咪,我叫:" + this.name; } } /// <summary> /// 吃(重寫父類虛方法) /// </summary> public override void Eat() { Console.WriteLine("我喜歡吃魚!"); } /// <summary> /// 叫(重寫父類方法) /// </summary> public override void Shout() { Console.WriteLine("喵!喵!喵!"); } } /// <summary> /// 羊(子類) /// </summary> class Sheep : Animal { string myName; public Sheep(string name) : base(name) { myName = name; } /// <summary> /// 名字(重寫父類屬性) /// </summary> public override string MyName { get { return "我是:羊羊,我叫:" + this.name; } } /// <summary> /// 吃(重寫父類虛方法) /// </summary> public override void Eat() { Console.WriteLine("我喜歡吃草!"); } /// <summary> /// 叫(重寫父類方法) /// </summary> public override void Shout() { Console.WriteLine("咩!咩!咩!"); } }

重寫(new)

new:覆蓋指的是不同類中有兩個或以上的返回類型,方法名,參數都相同,但是方法體不同的方法。

/// <summary>
    /// 動物類(父類)
    /// </summary>
    class Animal
    {
       /// <summary>
       /// 名字
       /// 說明:類和子類可訪問
       /// </summary>
       protected string name;


        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="name"></param>
        public Animal(string name)
        {
            this.name=name;
        }

        /// <summary>
        /// 名字(虛屬性)
        /// </summary>
        public virtual string MyName
        {
            get { return this.name; }           

        }

        /// <summary>
        /// 吃(虛方法)
        /// </summary>
        public virtual void Eat()
        {
            Console.WriteLine("我會吃!");
        }

        /// <summary>
        /// 叫(虛方法)
        /// </summary>
        public virtual void Shout()
        {
            Console.WriteLine("我會叫!");
        }
    }

    /// <summary>
    /// 狗(子類)
    /// </summary>
    class Dog:Animal
    {
        string myName;
        public Dog(string name): base(name)
        {
            myName = name;
        }        
        /// <summary>
        /// 名字(重寫父類屬性)
        /// </summary>
        public override string MyName
        {
            get { return "我是:狗狗,我叫:"+this.name; }
        }

        /// <summary>
        /// 吃(重寫父類虛方法)
        /// </summary>
        new  public   void Eat()
        {
            Console.WriteLine("我喜歡吃肉!");
        }

        /// <summary>
        /// 叫(重寫父類方法)
        /// </summary>
        public new void Shout()
        {
            Console.WriteLine("汪!汪!汪!");
        }
    }

技術分享圖片

可以看出,當派生類Dog的Eat()方法使用new修飾時,Dog的對象轉換為Animal對象後,調用的是Animal類中的Eat()方法。其實可以理解為,使用new關鍵字後,使得Dog中的Eat()方法和Animal中的Eat()方法成為毫不相關的兩個方法,只是它們的名字碰巧相同而已。所以, Animal類中的Eat()方法不管用還是不用virtual修飾,也不管訪問權限如何,或者是沒有,都不會對Dog的Eat()方法產生什麽影響(只是因為使用了new關鍵字,如果Dog類沒用從Animal類繼承Eat()方法,編譯器會輸出警告)。

我想這是設計者有意這麽設計的,因為有時候我們就是要達到這種效果。嚴格的說,不能說通過使用new來實現多態,只能說在某些特定的時候碰巧實現了多態的效果。

面向對象三大特性: 多態