zoukankan      html  css  js  c++  java
  • C#:为做基类而生的抽象类

    需求:我们需要一个Square类和Circle类能够打印出面积、颜色等成员信息;并且还希望他们能够打印出自己的特点。

    在不使用继承的情况下我们可以写出如下代码:

    namespace AbstractClassDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                Square square = new Square();
                square.ShowFeature();
                square.ShowInfo();
    
                Circle circle = new Circle();
                circle.ShowFeature();
                circle.ShowInfo();
    
                Console.ReadLine();
            }
        }
    
        class Square
        {
            public double SquareArea { get; set; }
    
            public string SquareColor { get; set; }
            //打印属性
            public void ShowInfo()
            {
                Console.WriteLine($"面积:{SquareArea},颜色:{SquareColor}");
            }
            //打印特征
            public void ShowFeature()
            {
                Console.WriteLine("我是长方形,对面平行且相等...");
            }
        }
    
        class Circle
        {
            public double CircleArea { get; set; }
    
            public string CircleColor { get; set; }
            //打印属性
            public void ShowInfo()
            {
                Console.WriteLine($"面积:{CircleArea},颜色:{CircleColor}");
            }
            //打印特征
            public void ShowFeature()
            {
                Console.WriteLine("我是圆形,我特圆....");
            }
        }
    }
    /* 输出:
    我是长方形,对面平行且相等...
    面积:0,颜色:
    我是圆形,我特圆....
    面积:0,颜色:
    */
    

    通过观察上面的代码,我们知道,除去ShowFeature方法在两个类中的功能实现略有不同外,其余成员都是相似的,所以根据我们学过的继承的知识,我们可以这样改写代码.

    定义基类Shape,将相似的部分声明到基类中,将会产生的变化的函数成员定义成virtual型,供派生类去重写

    namespace AbstractClassDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                Shape square = new Square();//赋值号左边使用基类型变量
                square.ShowFeature();
                square.ShowInfo();
    
                Shape circle = new Circle();//赋值号左边使用基类型变量
                circle.ShowFeature();
                circle.ShowInfo();
    
                Console.ReadLine();
            }
        }
    
        class Shape
        {
            public double Area { get; set; }
    
            public string Color { get; set; }
            //打印属性
            public void ShowInfo()
            {
                Console.WriteLine($"面积:{Area},颜色:{Color}");
            }
            //打印特征
            public virtual void ShowFeature()
            {
                //子类会自己在自己的类中重写的
            }
        }
    
        class Square : Shape
        {
            public override void ShowFeature()
            {
                Console.WriteLine("我是长方形,对面平行且相等...");
            }
        }
    
        class Circle : Shape
        {
            public override void ShowFeature()
            {
                Console.WriteLine("我是圆形,我特圆....");
            }
        }
    }
    /* 输出:
    我是长方形,对面平行且相等...
    面积:0,颜色:
    我是圆形,我特圆....
    面积:0,颜色:
    */
    

    到此为止,我们相当于快速回顾了重写和多态;在基类中有一个定义为virtual的函数成员ShowFeature,它并没有提供方法实体,因为我们觉得在这里并没有必要;

    基类型中的vitual函数成员不想提供代码实现而是想在子类中通过重写实现,那么我们就可以通过abstract修饰符将其声明为抽象成员:

    • 抽象成员没有方法体;
    • 抽象成员必须用abstract标记且必须是函数成员(函数成员包括:方法、属性、事件、索引器)
    • 抽象成员不能被private修饰且不能出现virtual修饰符;
    • 抽象成员专门为被基类重写而设计的
      所以我们可以将ShowFeature()方法改写成抽象方法,来重构代码
    1. 当我们将virtual关键字 改成 abstract关键字时,编译器提示了两个错误:
    2. 根据错误提示,我们将基类代码改写成如下形式:
    abstract class Shape
    {
        public double Area { get; set; }
    
        public string Color { get; set; }
        //打印属性
        public void ShowInfo()
        {
            Console.WriteLine($"面积:{Area},颜色:{Color}");
        }
        //打印特征
        public abstract void ShowFeature();
    }
    
    1. 至此我们就完美解决了:普通类型作为基类,ShowFeature(){}方法中虽提供了方法体,但却不想提供实现的问题。(完结撒花)。。。别急再往下看一下抽象类的定义吧。

    引入抽象类:专为被用作其他类的基类而设计的类。

    1. 抽象类不能被实例化抽象类中由于含有没有实现的函数,如果抽象类能够被实例化,那么当抽象类的引用调用到这个没有实体的函数时,计算机就不知道如何执行这个函数的行为,这样会导致程序崩溃;所以干脆编译器不让抽象类被实例化--设定抽象类被实例化的代码就会编译报错
    2. 抽象类可以有抽象成员、也可以有普通的非抽象成员:从上面的代码示例就可以验证这点--Shape类既有普通的属性Area、Color;普通的方法ShowInfo();还可以有抽象方法ShowFeature()
    3. 任何派生自抽象类的子类必须使用override关键字实现该类的所有抽象成员,除非派生类自己也是抽象类
      • 先解释前半句:如果说派生自抽象类的子类不把抽象类中的抽象成员全部重写了,岂不是又犯了:计算机无法执行没有行为的方法的问题?
      • 再解释后半句:后半句可以理解为--抽象类的派生类还是抽象类时,它可以不实现父类的抽象成员;因为这个抽象子类又不能实例化,不用怕计算机执行未提供实际行为的方法的问题;
      • 再说了:如果将来的确需要执行抽象类中定义的那个抽象函数,那么我们终会提供实现了全部抽象成员的子类实例来调用,所以不必心急。

    通过下面代码理解抽象类:

    namespace AbstractClassDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Shape shape = new Shape();//这行代码会报错:无法创建抽象类的实例
                Shape zhengfangxing = new ZhengFangXing();
                zhengfangxing.ShowFeature();
                Console.ReadLine();
            }
        }
    
        abstract class Shape
        {
            //非抽象的函数成员
            public double Area { get; set; }
            //非抽象的函数成员
            public string Color { get; set; }
            //非抽象的函数成员
            public void ShowInfo()
            {
                Console.WriteLine($"面积:{Area},颜色:{Color}");
            }
            //抽象成员:注意抽象成员不能被private修饰、不能被virtual修饰
            public abstract void ShowFeature();
        }
    
        abstract class Square : Shape
        {
            //将Square声明成抽象类,可以不必重写Shape类中的抽象方法了
        }
    
        class ZhengFangXing : Square
        {
            //终于有了一个子类实现了抽象成员--ShowFeature()方法
            public override void ShowFeature()
            {
                Console.WriteLine("我是特殊的长方形,我四条边都相等...");
            }
        }
    }
    /*输出:我是特殊的长方形,我四条边都相等...*/
    

    分析:Shape zhengfangxing = new ZhengFangXing(); zhengfangxing.ShowFeature();--这是由抽象类完成多态,相比上一篇的普通类的多态形式是不是更好一些?

    抽象类中的成员可以都是抽象成员,不含一个非抽象成员--当然如果真的是需要这样实现的话,有专门的类型--接口来实现;以上便是对抽象类的总结,记录下来以便以后查阅。

  • 相关阅读:
    za
    分享
    git
    javascript总结
    2019年IT行业的前景如何,JAVA和大数据适合女性么?
    java编程培训都学习哪些内容
    python中如何进行json转化
    Java技术分享:搭建Mybatis-generator工程
    2019年Java技术中当前流行的三大框架
    MySQL在阿里云服务器上的在线安装及配置
  • 原文地址:https://www.cnblogs.com/bigbosscyb/p/13882360.html
Copyright © 2011-2022 走看看