溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

發(fā)布時(shí)間:2020-09-01 08:50:49 來(lái)源:網(wǎng)絡(luò) 閱讀:444 作者:powertoolsteam 欄目:編程語(yǔ)言

在前面的文章中,我們介紹了編譯期多態(tài)、params關(guān)鍵字、實(shí)例化、base關(guān)鍵字等。本節(jié)我們來(lái)關(guān)注另外一種多態(tài):運(yùn)行時(shí)多態(tài), 運(yùn)行時(shí)多態(tài)也叫遲綁定。

 

運(yùn)行時(shí)多態(tài)或遲綁定、動(dòng)態(tài)綁定

在C#語(yǔ)音中,運(yùn)行時(shí)多態(tài)也叫方法重寫(xiě)(overriding),我們可以在子類(lèi)中overriding基類(lèi)的同簽名函數(shù),使用“virtual & override”關(guān)鍵字即可。

 

C#的New、Override關(guān)鍵字

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

創(chuàng)建一個(gè)console 示例工程,命名為InheritanceAndPolymorphism。在Program.cs基礎(chǔ)上,再添加2個(gè)類(lèi)文件,分別命名為ClassA.cs、ClassB.cs。拷貝如下代碼:

public class ClassA
    {        public void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }        public void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }

 

ClassB:

public class ClassB
    {        public void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }        public void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }

在上面的代碼中,我們可以看到ClassA、ClassB有同樣簽名的方法,可以在program.cs中直接使用。

我們對(duì)代碼再做休整,結(jié)構(gòu)如下:

/// <summary>
    /// ClassB, acting as a base class    /// </summary>
    public class ClassB
    {        public void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }        public void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }    /// <summary>
    /// Class A, acting as a derived class    /// </summary>
    public class ClassA : ClassB
    {        public void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }        public void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }

 

Program.cs

    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            ClassA x = new ClassA();
            ClassB y=new ClassB();
            ClassB z=new ClassA();

            x.AAA(); x.BBB(); x.CCC();
            y.AAA(); y.BBB();y.CCC();
            z.AAA(); z.BBB(); z.CCC();
        }
    }

F5,運(yùn)行代碼,結(jié)果如下:

ClassA AAA

ClassA BBB

ClassA CCC

ClassB AAA

ClassB BBB

ClassB CCC

ClassB AAA

ClassB BBB

ClassB CCC

但同時(shí),在VS的Output窗口,我們獲得了3個(gè)Warnings:

'InheritanceAndPolymorphism.ClassA.AAA()' hides inherited member

'InheritanceAndPolymorphism.ClassB.AAA()'. Use the new keyword if hiding was intended.

'InheritanceAndPolymorphism.ClassA.BBB()' hides inherited member

'InheritanceAndPolymorphism.ClassB.BBB()'. Use the new keyword if hiding was intended.

'InheritanceAndPolymorphism.ClassA.CCC()' hides inherited member

'InheritanceAndPolymorphism.ClassB.CCC()'. Use the new keyword if hiding was intended.

這些Warnings的原因是因?yàn)樽宇?lèi)和基類(lèi)的AAA、BBB、CCC方法簽名相同,盡管從執(zhí)行上看優(yōu)先執(zhí)行子類(lèi)同簽名的方法,但是可能會(huì)有潛在的問(wèn)題,故Warnings提出。

 

重構(gòu)實(shí)驗(yàn)

基于上面的Warning,我們手動(dòng)修改代碼,看看如何消除這些Warnings。

先給子類(lèi)添加new、override關(guān)鍵字試試:

/// <summary>
    /// Class A, acting as a derived class    /// </summary>
    public class ClassA : ClassB
    {        public override void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }        public new void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }

 

執(zhí)行的結(jié)果是報(bào)錯(cuò)了:

Error: 'InheritanceAndPolymorphism.ClassA.AAA()': cannot override inherited member 'InheritanceAndPolymorphism.ClassB.AAA()' because it is not marked virtual, abstract, or override

 

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

從這個(gè)錯(cuò)誤提示信息看,我們需要修改基類(lèi)方法,如添加virtual關(guān)鍵字。

/// <summary>
    /// ClassB, acting as a base class    /// </summary>
    public class ClassB
    {        public virtual void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }        public virtual void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }        public virtual void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }    /// <summary>
    /// Class A, acting as a derived class    /// </summary>
    public class ClassA : ClassB
    {        public override void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }        public new void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            ClassB y = new ClassB();
            ClassA x = new ClassA();
            ClassB z = new ClassA();

            y.AAA(); y.BBB(); y.CCC();
            x.AAA(); x.BBB(); x.CCC();
            z.AAA(); z.BBB(); z.CCC();

            Console.ReadKey();
        }
    }

執(zhí)行,則無(wú)Warning了,通過(guò)這個(gè)實(shí)例,我們得知通過(guò)在基類(lèi)添加Virtual關(guān)鍵字授權(quán)其子類(lèi)可override基類(lèi)同簽名方法的權(quán)限,方便了OOP的擴(kuò)展。

 

3個(gè)類(lèi)的運(yùn)行時(shí)多態(tài)

ClassA\ClassB基礎(chǔ)上,下面添加ClassC,看看3個(gè)類(lèi)繼承關(guān)系的運(yùn)行時(shí)多態(tài):

/// <summary>
    /// ClassB, acting as a base class    /// </summary>
    public class ClassB
    {        public  void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }        public virtual void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }        public virtual void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }    /// <summary>
    /// Class A, acting as a derived class    /// </summary>
    public class ClassA : ClassB
    {        public virtual void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }        public new void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }        public override void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }    /// <summary>
    /// Class C, acting as a derived class    /// </summary>
    public class ClassC : ClassA
    {        public override void AAA()
        {
            Console.WriteLine("ClassC AAA");
        }        public void CCC()
        {
            Console.WriteLine("ClassC CCC");
        }
    }    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            ClassB y = new ClassA();
            ClassB x = new ClassC();
            ClassA z = new ClassC();

            y.AAA(); y.BBB(); y.CCC();
            x.AAA(); x.BBB(); x.CCC();
            z.AAA(); z.BBB(); z.CCC();

            Console.ReadKey();
        }
    }

運(yùn)行結(jié)果:

ClassB AAA

ClassB BBB

ClassA CCC

ClassB AAA

ClassB BBB

ClassA CCC

ClassC AAA

ClassA BBB

ClassA CCC

如果基類(lèi)聲明了virtual 關(guān)鍵字,子類(lèi)可使用override修飾符實(shí)現(xiàn)運(yùn)行時(shí)多態(tài):只有在編譯器動(dòng)態(tài)決定是否被調(diào)用。

如果未標(biāo)明virtual或非virtual,則方法是否被調(diào)用在編譯期就能決定。

 

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

 

再看看下面的例子:

internal class A
    {        public virtual void X()
        {
        }
    }    internal class B : A
    {        public new void X()
        {
        }
    }    internal class C : B
    {        public override void X()
        {
        }
    }

F5運(yùn)行,結(jié)果報(bào)錯(cuò)了:

Error: 'InheritanceAndPolymorphism.C.X()': cannot override inherited member 'InheritanceAndPolymorphism.B.X()' because it is not marked virtual, abstract, or override

錯(cuò)誤的原因是A中定義了virtual的X函數(shù),在B中用new關(guān)鍵字隱藏了A中的X函數(shù)。當(dāng)C嘗試通過(guò)override關(guān)鍵字的時(shí)候,是獲得不了A中的virtual關(guān)鍵字X函數(shù)的,既在C中X函數(shù)為非Virtual的,故不能override。

 

切斷關(guān)系

internal class A
    {        public virtual void X()
        {
            Console.WriteLine("Class: A ; Method X");
        }
    }    internal class B : A
    {        public new virtual void X()
        {
            Console.WriteLine("Class: B ; Method X");
        }
    }    internal class C : B
    {        public override void X()
        {
            Console.WriteLine("Class: C ; Method X");
        }
    }    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            A a = new C();
            a.X();
            B b = new C();
            b.X();

            Console.ReadKey();
        }
    }

執(zhí)行結(jié)果如下:

Class: A ; Method X
Class: C ; Method X

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

在這里,我們通過(guò)在B類(lèi)中添加new Virtual修飾符,然后在C中即可使用B中Virtual的X函數(shù)了。

 

4個(gè)類(lèi)的運(yùn)行時(shí)多態(tài)

深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))

在上面繼承上,在運(yùn)行時(shí)多態(tài)中添加第四個(gè)類(lèi):ClassD。

/// <summary>
    /// Class A    /// </summary>
    public class ClassA
    {        public virtual void XXX()
        {
            Console.WriteLine("ClassA XXX");
        }
    }    /// <summary>
    /// ClassB    /// </summary>
    public class ClassB:ClassA 
    {        public override void XXX()
        {
            Console.WriteLine("ClassB XXX");
        }
    }    /// <summary>
    /// Class C    /// </summary>
    public class ClassC : ClassB
    {        public virtual new void XXX()
        {
            Console.WriteLine("ClassC XXX");
        }
    }    /// <summary>
    /// Class D    /// </summary>
    public class ClassD : ClassC
    {        public override void XXX()
        {
            Console.WriteLine("ClassD XXX");
        }
    }    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            ClassA a = new ClassD();
            ClassB b = new ClassD();
            ClassC c=new ClassD();
            ClassD d=new ClassD();
           
            a.XXX();
            b.XXX();
            c.XXX();
            d.XXX();

            Console.ReadKey();
        }
    }

 

執(zhí)行結(jié)果如下:

ClassB XXX

ClassB XXX

ClassD XXX

ClassD XXX

第一行輸出中,來(lái)自a.XXX()函數(shù) , 我們?cè)?ClassA中定義了XXX函數(shù),然后在ClassB中使用new關(guān)鍵字切斷了virtual關(guān)系--對(duì)子類(lèi)而言。因此XXX函數(shù)從ClassC開(kāi)始成為新的virtual函數(shù),在這個(gè)代碼中a是ClassD的實(shí)例,但是聲明的為ClassA,故從下往上找,找到ClassB的XXX函數(shù),打印并輸出結(jié)果。

 

永無(wú)止境的循環(huán)

 

/// <summary>
    /// Class A    /// </summary>
    public class ClassA
    {        public virtual void XXX()
        {
            Console.WriteLine("ClassA XXX");
        }
    }    /// <summary>
    /// ClassB    /// </summary>
    public class ClassB:ClassA 
    {        public override void XXX()
        {
            ((ClassA)this).XXX();
            Console.WriteLine("ClassB XXX");
        }
    }   
    /// <summary>
    /// Program: used to execute the method.    /// Contains Main method.    /// </summary>
    public class Program
    {        private static void Main(string[] args)
        {
            ClassA a = new ClassB();
            a.XXX();
           
        }
    }

運(yùn)行報(bào)錯(cuò):

Error: {Cannot evaluate expression because the current thread is in a stack overflow state.}

在這個(gè)例子中,((ClassA)this).XXX(); 導(dǎo)致了循環(huán)調(diào)用,修改為base.XXX即可修復(fù)這個(gè)強(qiáng)轉(zhuǎn)導(dǎo)致的循環(huán)調(diào)用。

 

結(jié)論

  • 在C#中,子類(lèi)對(duì)象可賦值給一個(gè)基類(lèi)對(duì)象;相反需要強(qiáng)轉(zhuǎn)。

  • override關(guān)鍵字用于子類(lèi)重寫(xiě)同簽名的基類(lèi)virtual函數(shù)

  • 用new和override可重寫(xiě)基類(lèi)virtual的同簽名函數(shù)

  • virtual修飾符的函數(shù),只能在運(yùn)行時(shí)決定是否被執(zhí)行

  • 函數(shù)未用virtual修飾,則在編譯期即可決定是否被調(diào)用

 

原文鏈接:Diving in OOP (Day 3): Polymorphism and Inheritance (Dynamic Binding/Run Time Polymorphism)


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI