面向对象---多态

(一).多态概念

让一个对象能够表现出多种状态(类型)

 

(二).实现多态三种方法

1.虚方法;2.抽象类;3.接口

 

(三).虚方法(关键字virtual

当父类的函数有实现时使用虚方法。使用虚方法意味着这个父类函数可以被子类重写,具体调用哪个被子类重新的函数,取决于父类对象装的是哪一个子类对象,但调用的始终是父类函数。

作用:最大可能地取消各个子类对象中的差异性,减少代码冗余,增强程序的可读性。

 

例子:

员工类:

 

    class Employee
    {
        public virtual void clockOut()
        {
            Console.WriteLine("员工九点打卡");
        }
    }
    class Manager:Employee
    {
        public override void clockOut()
        {
            Console.WriteLine("经理十点打卡");
        }
    }
    class Programmer:Employee
    {
        public override void clockOut()
        {
            Console.WriteLine("程序猿不打卡");
        }
    }

 

实现:

    class Program
    {
        static void Main(string[] args)
        {
            //员工九点打卡,经理十点打卡,程序猿不打卡
            Employee emp = new Employee();
            Manager mg = new Manager();
            Programmer pg = new Programmer();
            Employee[] emps = { emp, mg, pg };
            for (int i = 0; i < emps.Length; i++)
            {
                emps[i].clockOut();
            }
            Console.ReadKey();
        }
    }

结果:

 

 

(四).抽象类(使用关键字abstract)

 

 当父类的方法不知道如何实现的时候,可以将父类写成抽象类,将方法写成抽象方法。

 

注意:

1.抽象类不允许创建对象。

2.如果一个子类继承了一个抽象父类,那么它必须实现父类所有的抽象成员。

3.抽象成员必须标记为abstract,并且不能有任何实现。

4.抽象成员必须在抽象类中。抽象类可包含非抽象成员,并且抽象类中的实例成员可以不被子类发现。其中非抽象成员父类不可用,因为不能创建对象,但继承它的子类可以调用。

5.子类继承抽象类后,必须把父类所有的抽象成员重写。但如果这个子类也是抽象类,那就不用重写。

6.抽象成员的访问修饰符不能是private。

7.子类重写父类方法时返回的签名,必须跟抽象父类抽象方法的签名一样。签名指的是方法的返回值和参数。

 

例子:

动物类:

public abstract class Animals
    {
        //抽象类中可以有非抽象成员
        private int _age;    //年龄
        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
        public Animals(int age)
        {
            this.Age = age;
         }
        public abstract void Bark();  //动物叫的方式
    }

    public class Dog:Animals
    {
        public Dog(int age) : base(age)
        {

        }

        public override void Bark()  //重写父类函数
        {
            Console.WriteLine("小狗{0}岁了,会汪汪地叫~", this.Age);
        }
    }
    public class Cat : Animals
    {
        public Cat(int age) : base(age)
        {

        }

        public override void Bark()
        {
            Console.WriteLine("小猫{0}岁了,会喵喵地叫~", this.Age);
        }
    }

实现:

    class Program
    {
        static void Main(string[] args)
        {
            //小狗汪汪叫,小猫喵喵叫
            Animals dog = new Dog(3);
            Animals cat = new Cat(3);

            dog.Bark();
            cat.Bark();
            Console.ReadKey();
        }
    }

结果:

 

虚方法和抽象类的区别:

如果父类中的方法有默认的视线,并且父类需要被实例化时,可以将父类定义成一个普通类,用虚方法实现多态。

如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类

 

 

(五).序列化和反序列化

序列化:将对象转化为二进制。

反序列化:将二进制转化为对象。

作用:以二进制的形式传输数据。

要将一个类标记为被序列化的,在类的上方加上[Serializable]。

 

例子:对一个文本的内容进行序列化和反序列化

人类:

 

namespace Serialization_And_Deserialization
{
    [Serializable]
    public class Person
    {
        private string _name;    //名字
        
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        private char _gender;  //性别

        public char Gender
        {
            get { return _gender; }
            set { _gender = value; }

        }

        private int _age;  //年龄

        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
    }
}

 实现:

    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.Name = "chaara";
            p.Gender = '';
            p.Age = 12;

            //序列化,把文本文字(对象)转化为二进制存储在文本中
            using (FileStream fsWrite = new FileStream(@"C:\Users\Desktop\new.txt", FileMode.OpenOrCreate, FileAccess.Write))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fsWrite, p);
            }
            Console.WriteLine("序列化完毕!");

            //反序列化,把存储在文本的二进制转换成文字(对象)打印出来
            using (FileStream fsRead = new FileStream(@"C:\Users\Desktop\new.txt", FileMode.Open, FileAccess.Read))
            {
                BinaryFormatter bf = new BinaryFormatter();
                p = (Person)bf.Deserialize(fsRead);
                Console.WriteLine(p.Name);
                Console.WriteLine(p.Gender);
                Console.WriteLine(p.Age);
                Console.ReadKey();
            }
        }
    }

结果:

序列化

反序列化

 

 

 

(六).接口(关键字interface)

需要多继承时使用接口。接口就是一个规范、能力。接口命名一般为I...able。

 

注意:

1.接口的成员可以有:方法、属性、索引器、事件(本质上都是方法)。

2.为了多态,接口不能被实例化。

3.接口中的成员默认修饰符为public,不能有任何的实现。说白了就是光说不做,定义一组未实现的成员。

4.接口与接口之间可以继承,并且可以多继承。

5.实现接口的子类必须要实现该接口的全部成员。

6.一个类如果同时继承了类和接口,类必须排在接口前面。

7.显示实现接口是为了解决方法的重名问题。

 

例子:

接口:

namespace Interface
{
    public class Person : ISingingable
    {
        public void Singing()
        {
            Console.WriteLine("人在唱歌~");
        }
    }
    public interface IFlyable  //飞的能力
    {
        void Fly();  //接口中的成员不允许添加访问修饰符,默认为public;不允许有具体方法体的函数和字段(不存储数据),但有自动属性
    }

    public interface ISingingable  //唱歌的能力
    {
        void Singing();
    }

    public interface IDanceable  //唱歌的能力
    {
        void Dance();
    }
    public interface SuperIterface : ISingingable, IFlyable, IDanceable  //超级接口,实现接口与接口之间的多继承
    {

    }

    public class Bird : SuperIterface  
    {
        public void Fly()
        {
            Console.WriteLine("小鸟在飞翔~");
        }

        public void Dance()
        {
            Console.WriteLine("小鸟在跳舞~");
        }


        public void Singing()
        {
            Console.WriteLine("小鸟在唱歌~");
        }
    }
}

 实现:

    class Program
    {
        static void Main(string[] args)
        {
            ISingingable s1 = new Person();  //创建子类对象赋值给接口
            SuperIterface s = new Bird();
            s1.Singing();
            s.Fly();
            s.Dance();
            s.Singing();
            Console.ReadKey();
        }
    }

结果:

 

练习:真的鸭子 、橡皮鸭子和木头鸭子游泳方式

不同鸭子的接口

namespace 接口练习
{
    //真的鸭子会游泳  橡皮鸭子会游泳  木头鸭子不会游泳

    public interface ISwingingable
    {
        void Swinging();
    }
    public class RealDuck:ISwingingable
    {
        public void Swinging()
        {
            Console.WriteLine("真的鸭子靠翅膀脚丫子游泳");
        }
    }

    public class RubberDuck : ISwingingable
    {
        public void Swinging()
        {
            Console.WriteLine("橡皮鸭子飘在水中自由泳");
        }
    }

    public class WoodDuck : ISwingingable
    {
        public void Swinging()
        {
            Console.WriteLine("木头鸭子太重了游不动");
        }
    }
}

实现:

    class Program
    {
        static void Main(string[] args)
        {
            ISwingingable realDuck = new RealDuck(); //创建真鸭子对象
            ISwingingable rubberDuck = new RubberDuck();//创建橡皮鸭子对象
            ISwingingable woodDuck = new WoodDuck();  //创建木头鸭子对象

            realDuck.Swinging();
            rubberDuck.Swinging();
            woodDuck.Swinging();
            Console.ReadKey();
        }
    }

结果:

 

 

课后思考:

什么时候用虚方法?

什么时候用抽象类?

什么时候用接口?

 

posted @ 2017-10-15 22:17  张晨子  阅读(355)  评论(2编辑  收藏  举报