多态的使用 虚方法、抽象类、接口

1、新建一个person类

public class Person
    {
        public string Name;
        
        public Person(string name)
        {
            this.Name = name;
        }
        public void SayHello()
        {
            Console.WriteLine($@"我是人,是叫{Name}");
        }
    }

2、新建几个person的子类

public class Chinese : Person
    {
        public Chinese(string name) : base(name)
        { }
        public void SayHello()
        {
            Console.WriteLine("我是中国人,我叫{0}", this.Name);
        }
    }
    public class Japanese : Person
    {
        public Japanese(string name) : base(name)
        { }
        public void SayHello()
        {
            Console.WriteLine("我是日本人,我叫{0}", this.Name);
        }
    }
    public class Korea : Person
    {
        public Korea(string name) : base(name)
        { }
        public void SayHello()
        {
            Console.WriteLine("我是韩国人,我叫{0}", this.Name);
        }
    }
    public class American : Person
    {
        public American(string name) : base(name)
        { }
        public void SayHello()
        {
            Console.WriteLine("我是美国人,我叫{0}", this.Name);
        }
    }

3、这时候,创建几个不同的对象,把内容给展示出来

        static void Main(string[] args)
        {
            //多态:让一个对象能够表现出多种的状态(类型)
            
            Chinese cn1 = new Chinese( "李雷");
            Chinese cn2 = new Chinese("韩梅梅");
            Japanese j1 = new Japanese("松下幸之助");
            Korea k1 = new Korea("金秀贤");
            American a1 = new American("科比");
            American a2 = new American("奥尼尔");
            List<Person> list = new List<Person>() {cn1,cn2,j1,k1,a1,a2 };
            foreach (Person p in list)
            {
                p.SayHello();
            }
            Console.ReadKey();
        }

4、那么问题来了,这里每个对象调用的都是父类的方法,没有调用自己类的方法,如果我希望调用的是自己的方法,那该怎么办呢?

foreach (Person p in list)
            {
                if (p is Chinese)
                {
                    Chinese cn = (Chinese)p;
                    cn.SayHello();
                }
                else if(p is Korea)
                {
                    Korea ko = (Korea)p;
                    ko.SayHello();
                }
                else if (p is Japanese)
                {
                    Japanese jp = (Japanese)p;
                    jp.SayHello();
                }
                else if (p is American)
                {
                    American am = (American)p;
                    am.SayHello();
                }
            }
            Console.ReadKey();

5、这里使用了if  else 进行类型判断后转换的方法。除此之外还有没有别的方法呢?有三种方法:A、虚方法   B、抽象类    C、接口

A、将父类的方法标记为虚方法,使用virtual,在子类的方法前面加override

    public class Person
    {
        public string Name;
        
        public Person(string name)
        {
            this.Name = name;
        }
        public virtual void SayHello()
        {
            Console.WriteLine($@"我是人,是叫{Name}");
        }
    }
    public class Chinese : Person
    {
        public Chinese(string name) : base(name)
        { }
        public override void SayHello()
        {
            Console.WriteLine("我是中国人,我叫{0}", this.Name);
        }
    }
    public class Japanese : Person
    {
        public Japanese(string name) : base(name)
        { }
        public override void SayHello()
        {
            Console.WriteLine("我是日本人,我叫{0}", this.Name);
        }
    }
    public class Korea : Person
    {
        public Korea(string name) : base(name)
        { }
        public override void SayHello()
        {
            Console.WriteLine("我是韩国人,我叫{0}", this.Name);
        }
    }
    public class American : Person
    {
        public American(string name) : base(name)
        { }
        public override void SayHello()
        {
            Console.WriteLine("我是美国人,我叫{0}", this.Name);
        }
    }

说明:调用了父类的sayHello,然而这个list中装的是子类的对象,于是就用子类的方法。如果这时存入的是Person的对象,依然会使用Person的方法。

B、用抽象类实现。抽象类中,写抽象方法。抽象方法是没有方法体的(即,没有大括号)。这个方法是没法运行的,他的存在意义就是让子类来实现它。

class Program
    {
        static void Main(string[] args)
        {
            Chinese cn1 = new Chinese( "李雷");
            Chinese cn2 = new Chinese("韩梅梅");
            Japanese j1 = new Japanese("松下幸之助");
            Korea k1 = new Korea("金秀贤");
            American a1 = new American("科比");
            American a2 = new American("奥尼尔");
            //Person p1 = new Person("Aman");
            List<Person> list = new List<Person>() { cn1, cn2, j1, k1, a1, a2 };// ,p1};
            foreach (Person p in list)
            {
                p.SayHello();
            }
            Console.ReadKey();
        }

    }

public abstract class Person
    {
        public string Name;
        
        public Person(string name)
        {
            this.Name = name;
        }
        public abstract void SayHello();//抽象方法  
     //{}
}

注意这里的区别,如果是A虚方法,那么他自己也是可以运行的,如果是抽象的,就没法创建对象了。(接口也不能创建对象)

C、接口

接口是一种规范,也是一种能力。以 I 开头 ,以able结尾 如  IFlyable。

接口中不需要访问修饰符,都是public的。

接口中不能写具有方法体的函数,光说不做,只是定义了一组未实现的成员。

接口中不能有字段。(但是可以有  string Name {get;set;} 这样的自动属性。其实这也是方法)

 接口和接口之间可以结成,并且可以多继承。

接口并不能用去继承一个类。实现接口的类,必须实现所有的接口。

interface ISayHelloable
    {
        string Name { get; set; }
        void SayHello();
    }

    public class Chinese: ISayHelloable
    {
        public Chinese(string inputName)
        {
            Name = inputName;
        }

        string chineseName;
        public string Name
        {
            get{return chineseName ; }
            set{ chineseName = value;}
        }

        public void SayHello()
        {
            Console.WriteLine($@"我是中国人,我的中国名字叫{Name}");
        }
    }
    public class American : ISayHelloable
    {
        public American(string inputName)
        {
            Name = inputName;
        }
        string AmericanName;
        public string Name
        {
            get { return AmericanName; }
            set { AmericanName = value; }
        }
        public void SayHello()
        {
            Console.WriteLine($@"我是美国人,我的美国名字叫{Name}");
        }
    }

首先定义一个接口,并用两个类去实现这个接口。

再创建两个不同的类对象,因为他们都实现了这个接口,于是定义一个List把他们装进来。

然后用接口的方法来分别调用各自的方法。

static void Main(string[] args)
        {
            List<ISayHelloable> persons = new List<ISayHelloable>();
            persons.Add(new Chinese("李磊"));
            persons.Add(new American("Adam"));
            persons.Add(new Chinese("韩梅梅"));
            persons.Add(new American("John"));
            foreach (ISayHelloable p in persons)
            {
                p.SayHello();
            }
            Console.ReadKey();

        }

 综上:

1、构建“主从”这种关系的类时,使用虚方法。

2、构建“父子”这种关系的类时,使用抽象。

3、在哪里都可以用接口。

接口的优势:A、多继承。B、相互之间无关的类实现你的接口。C、想指定一个特定数据类型的行为,但是不用去关心由谁来实现这一行为。

说的不全面,暂且这么记,以后对这个问题认识深刻后,再来修改。

原文地址:https://www.cnblogs.com/adamgq/p/8387088.html