• 【C#】OOP之多态那点事


                           

    看上面的UML图,我们创建一个抽象的Instrument类,类中有一个抽象方法paly,然后所有的子类都继承这个类并实现paly方法。(若不懂继承,请参照另一篇:OOP之继承那点事

    我们来看一下类的实现:

        public abstract class Instrument
        {
            public abstract void Play();
        }
    
        public class Guitor : Instrument
        {
            public override void Play()
            {
                Console.WriteLine(string.Format("Play {0}", this.GetType().Name));
            }
        }
    
        public class Paino : Instrument
        {
            public override void Play()
            {
                Console.WriteLine(string.Format("Play {0}", this.GetType().Name));
            }
        }
    
        public class Violin : Instrument
        {
            public override void Play()
            {
                Console.WriteLine(string.Format("Play {0}", this.GetType().Name));
            }
        }
    View Code

    在每个子类方法里,我们直接出去字符串。

      class Program
        {
            static void Main(string[] args)
            {
                Guitor g = new Guitor();
                g.Play();
    
                Paino p = new Paino();
                p.Play();
    
                Violin v = new Violin();
                v.Play();
    
                Console.ReadLine();
            }
        }
    View Code

    在Main方法里,我们创建了三个对象,然后分别输出。 这个说在我们还没开始多态之前的写法,好麻烦有木有(木有?蹲角落写100个乐器的paly).那什么是多态呢?

    什么是多态:一种形态的多种表现形式(好抽象...)

    THINK IN JAVA上写到:多态是消除类型之间的耦合关系(还是很抽象)

      直接看例子:

        class Program
        {
            static void Main(string[] args)
            {
                PlayInstrument(new Guitor());
                PlayInstrument(new Paino());
                PlayInstrument(new Violin());
    
                Console.ReadLine();
            }
    
            public static void PlayInstrument(Instrument instrument)
            {
                instrument.Play();
            }
        }
    View Code

      这样的输出是和上面的例子是一样的,我们改变了什么,我们提供了一个方法,把3个子类的引用放了进去,呀,为什么PlayInstrument的形参是Instrument的对象,这就是多态的关键之处,

    我总结了一句话:子类的引用(new Guitor())指向父类的对象(Instrument instrument) ;

      

           static void Main(string[] args)
            {
                Instrument instrument = new Guitor();
                instrument = new Paino();
                instrument = new Violin();
    
                Console.ReadLine();
            }
    View Code

       这个好神奇有木有,我初学时间也觉得,这个好神奇,这个这么玩的,让我来带领大家进入神秘的多态空间。

      

      

      向上转型

         

           static void Main(string[] args)
            {
                Guitor gutior = new Guitor();
                Instrument instrument = gutior;
    
    
                Console.ReadLine();
            }
    View Code

    向上转型,就说把子类的类型转成父类的,这样是安全的,看上面的例子,如果在VS IDE工具中查看,是没有编译报错的,这时为什么呢?我们来看张图。

    这个圆我们把他当作堆(heap)来看,(这没有画栈,因为指向讨论向上转型的安全).我们来看一下Guitor里面包含了Instrument的所有的东西(除了构造,如果说你点不出来私有化的东西,你可以尝试用反射,它的确存在) ,这样我们把大块变成小块是不是很安全呢,因为我大块拥有小块里面所有的东西,所以说向上转型是安全的。

      

    注:相反来说,向下转型是危险的,因为小块变成大块,你不可以控制里面的东西。(协变和逆变概念也差不多,我比较喜欢叫成和谐的变->安全,逆天的变->危险)

    这样的话,我们把大块转换成小块(Instrument instrument=new Guitor()),我们只能调用到小块的东西了(所以我们在设计的时候,一般会用接口去限定)

      

      接口其实是应该单独拉出来谈的,但是由于接口基本概念不多,只是在我们OO设计中,接口用处很大,这里属于设计范围,在多态中,用接口做父类和用类写法一样的,可以去试试。

      

      总结一下:

      1.向上转型以后,虽然引用还是原本的子类,但是只能用父类的方法了(想想大块变小块)

      2.父类方法被子类重写了(virtual,override)以后,向上转型以后,调用相同的方法还是大块的(因为小块的被重写了,这样说感觉很牵强,因为如果我们在子类中用base关键字还是能调用父类的同名方法,至于这块的内存的调用,我一直没找到相关资料,如果有人知道,请分享一下,万分感谢)。

      3.接口和抽象类(类)在使用多态的上面是同一个形式

      

      感觉这边写的不好...望大家补充和指出不足,谢谢了。

  • 相关阅读:
    C语言修炼-第2天
    static_cast, dynamic_cast, reinterpret_cast, const_cast的区别
    构造函数不能为虚函数的原因
    matlab2016b ubuntu命令行安装 + matconvnet的安装
    python debug open_files
    构造函数不能被继承的原因
    NNVM代码阅读
    ncnn阅读
    Deep TEN: Texture Encoding Network
    git命令笔记
  • 原文地址:https://www.cnblogs.com/guochenkai/p/3897461.html
Copyright © 2020-2023  润新知