第十八讲:多态

面向对象的三大特征:
    封装
    继承
    多态
    
回顾:
    为什么要继承?
        方便在分类编写代码后,子类可以从父类获得数据和代码
    
    子类(派生类)可以从父类(基类)中哪些数据和代码?那些绝对不能获取到?
        除构造函数和析构函数外,静态类不可以继承外
    
    如何在子类中显示调用基类的成员
        base关键定
    
    如何调用基类的构造函数
        本类调用 this
        父类调用 base
    
    sealed关键字的用法,密封类和密封虚方法和虚属性
        多态?
        
        
主要内容:
    1. 现实中的多态与编程中的多态
        多态:同一个操作用于不同的对象,可以有不同的解释,产生不同的结果,这就是多态性。
        
        多态必通过派生类覆写基类中的虚函数虚方法来实现
        
        C#支持两种多态性:
            编译时 --> 重载(overload)
            运行时 --> 虚方法(virtual)和重写(override)
            
    2. 虚方法和重写
        虚成员
            就是指在基类中申明了方法,属性,索引器或事件,也做一个简单的处理
            
            使用virtual关键字将成员申明为虚成员
            例:
                public virtual double Area()
                {//计算面积,虚方法,等待被重写
                    return x*y;
                }
                
            重写或覆写
            例:
                public override double Area()
                {//计算面积,覆写虚方法
                    return PI*x*y;
                }
                
            
    3. 面积计算器实例
    
    4. 虚方法规则
        默认情况下,方法是非虚拟的。不能重写非虚方法。
        
        virtual修饰符不能与static,abstract(抽象),private或override修饰符一起使用
        
        除了声明和调用语法不同外,虚拟属性的行为和抽象方法一样。
        
        在静态属性上使用virtual修饰符是错误的
        
        通过包括使用override修饰符的属性声明,可以派生类中重写虚拟继承属性
        
        
    5. 隐藏基类的成员
        若要隐藏继承的成员,则使用new修饰符修饰该成员
        例:
            public calss BaseC
            {
                public int x;
                public void Invoke()
                {
                    //方法体
                }
            }
            
            public calss DerivedC:BaseC
            {
                public new void Invoke()
                {
                    //方法体
                }
            }
            
            
    6. 隐藏基类成员 实践
        
    7. 抽象类
        所有对象都是用类实例化出来的,反之,所有类都是来描述对象的吗?
        
        一个类中没有包含足够的信息来描述一个具体的对象
        
        抽象类的修饰符abstract
        
        abstract可以将类修饰为抽象类,也可以将类成员修饰为抽象成员。
        
        例:
        public abstract calss A //用修饰符abstract将类修饰为抽象类
        {
            //用修饰符abstract将类成员修饰为抽象成员
            //注意:抽象方法没有实现体(即没有方法体)
            public abstract void GoTo();
            //用修饰符abstract将类成员修饰为抽象成员
        }
        
        //继承并实现上面抽象类的派生类
        
        public class B:A
        {
            public override void GoTo()
            //也使用override关键字来实现抽象基类中的抽象方法
            {
                //实现上面的抽象的方法
            }
        }
        
        
    抽象类规则:
        1. 抽象类不能实例化
        2. 抽象类可以包含抽象方法和抽象属性,也可包含普通的类成员
        3. 只要一个类中有一个抽象方法,那么这个方法所在类必须是个抽象类
        4. 不能用sealed修饰符修改抽象类,因为使用它就意味着抽象类不能被继承
        5. 从抽象类派生的非抽象类必须实现全部的抽象方法和抽象属性,包括继承来的。
        
    抽象方法的规则:
        1. 抽象方法是隐式的虚方法
        2. 只允许在抽象类中使用抽象方法的声明
        3. 因为抽象方法声明不提供实现方法体,所以没有方法体,方法只是以一个分号结束,并且在签名后没有大括号({}).
        4. 实现,由一个派生类中的方法来实现,重写的方法用override关键字,此重写方法是非抽象类的一个成员
        5. 子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。也可以不实现抽象方法,留给后代实现,这时子类仍旧是一个抽象类,必须声明为abstract
        6. 继承的抽象方法不可以被隐藏
        7. 在抽象方法声明中使用static或virtual修饰符是错误的。
        
    除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
    
        1. 在静态属性上使用abstract修饰符是错误的
        2. 在派生类中,通过包括使用override修饰符的属性声明,可以重写抽象的继承属性。
        
    最后,一个很有必要单独提醒的是,实现抽象方法(在派生类中重写基类的抽象方法)必须与被实现的抽象方法的返回类型,方法名,参数(顺序和类型)都完全相同,不同的是使用的abstract和override这两个关键字的不同。

       

我自己写了一段简单代码和MSDN上的抽象类代码的研究:

namespace Con18
{
    /// 
    /// 定义一个抽象类
    /// 
    public abstract class Shapes
    {
        public double x;
        public double y;

        string id;

        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        public Shapes() { }

        public Shapes(double a, double b)
        {
            this.x = a;
            this.y = b;
        }

        /// 
        /// 这里我的理解是,抽象属性的这个属性应该是自定义属性,不能对对字段的封装后的属性进行修改为抽象属性
        /// 
        public abstract double Area
        {
            get;
        }

        public abstract double ShapeArea(double x,string id);

        //public override string ToString()
        //{
        //    return string.Format("{0:F2}", Area);
        //}
    }

    /// 
    /// 继承抽象类,实现抽象属性和抽象方法
    /// 
    public class sh : Shapes
    {
        /// 
        /// 重写基类的抽象属性
        /// 
        public override double Area
        {
            get { return base.x * base.y; }
        }

        /// 
        /// 调用基类的构造函数
        /// 
        /// 
        /// 
        public sh(double a, double b)
            : base(a, b)
        { 
            
        }

        /// 
        /// 重写基类的抽象方法
        /// 
        /// 
        /// 
        /// 
        public override double ShapeArea(double x,string id)
        {
            base.ID = id;
            return x * x * 3.14;
        }
    }

    ///==============================================================================

    /// 
    /// MSDN实例研究,抽象类
    /// 
    public abstract class Shape
    {
        //这是一个普通的字段name
        private string name;

        /// 
        /// 这是一个抽象类的构造函数
        /// 
        /// 
        public Shape(string s)
        {
            //调用字段name的属性 
            Id = s;
        }

        /// 
        /// 这是抽象类的一个普通属性Id
        /// 
        public string Id
        {
            get
            {
                return name;
            }

            set
            {
                name = value;
            }
        }

        /// 
        /// 这个是抽象类中的一个只读抽象属性Area
        /// 
        public abstract double Area
        {
            get;
        }

        /// 
        /// 这是抽象类对ToString方法的重写操作
        /// 这个地方我还搞不清楚,跑了一下断点,大致理解是,前台执行打印对象时,自动会将
        /// 对象名转化为字符串,这里重写toString方法,就为了修改字符串打印方法体,实现自
        /// 已的需求。
        /// 
        /// 
        public override string ToString()
        {
            return Id + " Area = " + string.Format("{0:F3}", Area);
        }
    }

    /// 
    /// 抽象类的实现,图形是抽象类,继承并实现正方形的面积
    /// 
    public class Square : Shape
    {
        private int side;

        public Square(int side, string id)
            : base(id)//这里调用基类的构造函数
        {
            this.side = side;
        }

        public override double Area
        {
            get
            {
                //获取边长,返回正方形的面积
                return side * side;
            }
        }
    }

    /// 
    /// 实现图形抽象类为圆
    /// 
    public class Circle : Shape
    {
        private int radius;

        public Circle(int radius, string id)
            : base(id)
        {
            this.radius = radius;
        }

        public override double Area
        {
            get
            {
                // Given the radius, return the area of a circle: 
                return radius * radius * System.Math.PI;
            }
        }
    }

    /// 
    /// 实现图形抽象类为长方形
    /// 
    public class Rectangle : Shape
    {
        private int width;
        private int height;

        public Rectangle(int width, int height, string id)
            : base(id)
        {
            this.width = width;
            this.height = height;
        }

        public override double Area
        {
            get
            {
                //获取长方形的长宽计算其面积
                return width * height;
            }
        }
    } 



}

其实抽象类理解了,虚方法虚属性应该都不在话下了。虚方法属性这些,只所以有这种定义就是方便开发人员以后对其进行改写,普通的方法属性是不能进行改写操作的,他们的区别只是修饰关键字的不同,virtual和override,方法签名中除这两个关键字不同,其它应该必须相同了。而抽象呢,大至跟virtual定义的虚方法和属性相同,不同的是抽象的只能被继承,在前台是不是能直接调用抽象类中的抽象方法或属性的,而且,抽象的方法还没有方法体呢。


请看前台调用抽象类的代码:

namespace Con18
{
    class Program
    {
        static void Main(string[] args)
        {
            sh s = new sh(10,10);

            double area = s.ShapeArea(5, "test");

            Console.WriteLine(area + "====" + s.ID);

            //s.x = 1.2;
            //s.y = 3.3;

            Console.WriteLine(s.Area);
//==============MSDN实例代码的调用======================================
            Shape[] shapes = 
        { 
            new Square(5, "Square #1"), 
            new Circle(3, "Circle #1"), 
            new Rectangle( 4, 5, "Rectangle #1") 
        };

            System.Console.WriteLine("Shapes Collection");
            foreach (Shape s1 in shapes)
            {
                System.Console.WriteLine(s1);
            }

            Console.ReadKey();

        }
    }
}
执行的结果:

第十八讲:多态_第1张图片


希望能和大家一起学习研究,有好的群啥的,也能让俺参与一下。

你可能感兴趣的:(C#学习历程,(C#基础))