C#面向对象编程-类和对象(抽象类和密封类)

抽象类和抽象方法

如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个基类,这样的类就是抽象类,在抽象类中声明方法时,如果加上abstract时就是抽象方法
抽象类的概述及声明抽象类与非抽象类的主要区别:(1)抽象类不能直接被实例化。
(2)抽象类中可以包含抽象成员,但非抽象类中不可以。
(3)抽象类不能被密封。

抽象方法的概述及声明在抽象类中也可以使用关键字absract定义抽象方法,要求所有派生的非抽象类都要重载实现抽象方法,引入抽象方法的原因在于抽象类本身是一种抽象概念,有的方法并不需要具体实现,而是留下来让派生类重载实现。声明抽象方法时需注意:
(1)抽象方法必须声明在抽象类中。
(2)声明抽象方法时,不能使用virtual、static和private修饰符。
(3)抽象方法声明引入一个新的方法,但是不提供具体的实现。
(4)当从抽象类中派生一个非抽象类时,需要在非抽象类中重写所有抽象类中的方法,提供具体实现细节,重写抽象方法时候使用override关键字。

using System;
namespace Project16
{
    //定义基类Shape
    public abstract class Shape        //声明一个抽象类的图形
    {
        //protected的作用:允许派生类访问它的基类成员
        protected string Color;        //表示图形的颜色
        //构造函数的作用帮助用户初始化对象,也就是给对象的每个属性依次赋值
        public Shape(string Color)     //定义带参的构造函数,为图形的颜色赋值
        {
            this.Color = Color;
        }
        public string GetColor()        //获取图形颜色的方法GetColor
        {
            return Color;
        }
        public abstract double GetArea();   //表示图形的面积
        //(1) 抽象方法必须声明在抽象类中。
        //(2) 声明抽象方法时,不能使用virtual、static和private修饰符。
        //(3) 抽象方法声明引入一个新的方法,但是不提供具体的实现。
    }
    //定义Cirle类,从Shape类中派生
    public class Circle : Shape      //圆形
    {
        //private的作用:只有在同一类中的方法,才能够去访问该变量
        private double Radius;      //圆的半径
        //通过base关键字,指定创建派生类实例时应调用的基类构造函数。
        public Circle(string Color, double Radius) : base(Color)
        {
            this.Color = Color;
            this.Radius = Radius;
        }
        //当从抽象类中派生中一个非抽象类时,需要使用override关键字,来实现非抽象类中的方法
        public override double GetArea()      //重写抽象方法
        {
            return System.Math.PI * Radius * Radius;
        }
    }
    //派生类Rectangular,从Shape类中派生
    public class Retangular : Shape       //矩形
    {
        protected double Length, Width;   //声明长和宽
        public Retangular(string Color, double Length, double Width) : base(Color)  //构造函数
        {
            this.Color = Color;
            this.Length = Length;
            this.Width = Width;
        }
        public override double GetArea()    //重写方法
        {
            return (Length * Width);
        }
        public double PerimeterIs()   //周长
        {
            return (2 * (Length + Width));
        }
    }
    //派生类Square,从Retangular类中派生
    public class Square : Retangular        //正方形
    {
        public Square(string Color, double Side) : base(Color, Side, Side) {; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Circle Cir = new Circle("黄色", 4.0);
            Console.WriteLine("圆形的颜色是:{0},它的面积是:{1}", Cir.GetColor(), Cir.GetArea());
            Retangular Rect = new Retangular("红色", 6.0, 8.0);
            Console.WriteLine("矩形的颜色是:{0},它的面积是:{1},它的周长是:{2}",
                Rect.GetColor(), Rect.GetArea(), Rect.PerimeterIs());
            Square Squ = new Square("绿色", 5.0);
            Console.WriteLine("正方形的颜色是:{0},它的面积是:{1},它的周长是:{2}",
                Squ.GetColor(), Squ.GetArea(), Squ.PerimeterIs());
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示了抽象类与抽象方法的使用。在代码中,首先使用abstract关键字将Shape类声明为抽象类,在该类中定义了变量Color,用于表示颜色;定义了带参的构造函数,用于给变量Color赋值;定义了GetColor方法,用于获取变量Color的数据;还声明了一个抽象方法GetArea,用于获取图形的面积。这里需要注意,抽象方法必须声明在抽象类中,并且不能包含方法体。接着,通过Shape类派生Circle类和Rectangular类,而在这两个类中都重写了抽象方法GetArea,才可以计算出具体面积。然后,声明Square类继承于Rectangular类,并通过base关键字,指定创建派生类实例时应调用的基类构造函数。

圆形的颜色是:黄色,它的面积是:50.2654824574367
矩形的颜色是:红色,它的面积是:48,它的周长是:28
正方形的颜色是:绿色,它的面积是:25,它的周长是:20

抽象类与接口的区别

很多C#的初学者在编程时都容易把抽象类和接口搞混,本文就为大家从概念上讲解抽象类和接口的区别:

  1. 抽象类
    含有abstract修饰符的class即为抽象类,抽象类是特殊的类,只是不能被实例化,可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例;
  2. 接口
    接口是引用类型,类似于类。接口和抽象类的相似之处有三点:
    (1) 不能实例化。
    (2) 包含未实现的方法声明。
    (3) 派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员。
  3. 两者的语法区别
    (1) 抽象类可以有构造方法,接口中不能有构造方法。
    (2) 抽象类中可以有普通成员变量,接口中没有普通成员变量
    (3) 抽象类中可以包含静态方法,接口中不能包含静态方法
    (4) 一个类可以实现多个接口,但只能继承一个抽象类。
    (5) 抽象类实现的具体方法默认为虚方法,但实现接口的类中的接口方法却默认为非虚方法,当然用户也可以声明为虚方法

密封类和密封方法

如果所有类都可以被继承,那么很容易导致继承的滥用,进而使类的层次结构体系变得十分复杂,这样使开发人员对类的理解和使用变得十分困难。为了避免滥用继承,C#中提出了密封类的概念。

  1. 密封类概述及声明
    密封类可以用来限制扩展性,如果密封了某个类,则其他类不能从该类继承;如果密封了某个成员,则派生类不能重写该成员的实现。
  2. 密封方法的概述及声明
    并不是每个方法都可以声明为密封方法,密封方法只能用于对基类的虚方法进行实现,并提供具体的实现。所以,声明密封方法时,sealed修饰符总是和override修饰符同时使用。
    编写程序,定义一个密封方法,并对它进行重写。
using System;
namespace Project17
{
    public class MyClass1
    {
        public virtual void Write()
        {
            Console.WriteLine("这是一个未密封的方法");
        }
    }
    public class MyClass2:MyClass1
    {//继承之后需要对虚方法Write进行重写
        public sealed override void Write()
        {
            Console.WriteLine("这是一个密封的方法");
        }
    }
    public class MyClass3:MyClass2
    {
        //public override sealed void Write()
        //{
        //    Console.WriteLine("重写密封方法");
        //}
        //继承成员“MyClass2.Write()”是密封的,所以无法进行重写 
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass2 myClass2 = new MyClass2();
            myClass2.Write();
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示了密封方法的使用。在代码中,声明一个类MyClass1,该类中声明一个虚方法Method。然后声明类MyClass2,该类继承自MyClass1类,在密封类MyClass2中密封并重写MyClass1类中的虚方法Method。如果再声明类MyClass3,继承于MyClass2,并重写MyClass2类中的密封方法Method,编译器是不允许的。

这是一个密封的方法
  1. 密封类与密封方法的使用
    密封类除了不能被继承外,与非密封类的用法大致相同,而密封方法则必须通过重写基类中的虚方法来实现。
    编写程序,通过密封类与密封方法输出用户的基本信息。
using System;
namespace Project18
{
    public class MyClass1
    {
        public virtual void ShowInfo() //虚方法,用来显示信息
        {
        }
    }
    public sealed class MyClass2 : MyClass1 //密封类,继承 MyClass1
    {
        private string _id = "";
        private string _name = "";
        public string ID
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
            }
        }
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
        public sealed override void ShowInfo()
        {
            Console.WriteLine("我是{0},我的ID是{1}", Name, ID);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass2 myclass2 = new MyClass2();
            myclass2.ID = "BH0001";
            myclass2.Name = "张三";
            myclass2.ShowInfo();
            Console.ReadKey();
        }
    }
}

【程序分析】本例演示了密封类与密封方法的使用。在代码中,声明一个类MyClass1,该类中声明了一个虚方法ShowInfo,用来显示信息。然后声明一个密封类MyClass2,继承自MyClass1类,在MyClass2密封类中声明两个公共属性,分别用来表示用户编号和名称。接着密封并重写myClass1基类中的虚方法ShowInfo,并提供具体的实现。最后在主程序类Program的Main方法中实例化MyClass2密封类的一个对象,然后使用该对象访问myClass2密封类中的公共属性和密封方法。这里需要注意的是,在声明密封方法时,必须通过重写基类中的虚方法实现。

我是张三,我的ID是BH0001
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值