C#中抽象类与接口详解

[https://blog.csdn.net/qq_42672770/article/details/107730430]

1.抽象类与接口的概念

类是具有相同或相似结构、操作和约束规格的对象组成的结合。而对象是某一类的具体实例化。每一个类都是具有某些共同特征的对象的抽象
如下图,我们可以将所有的图形归为图形类,图形类即为一个抽象类(父类),但是对于具体的图形是三角形、四边形或者其他图形,无法准确描述。但是三角形、四边形等又都是继承于图形类的子类。具体是哪一类四边形又可分为正方形、平行四边形等
在多态机制中并不需要将父类初始化为对象,需要的是子类对象,图形类(父类)不能抽象出任何一种图形,但子类却可以。
继承抽象类的所有子类需要将抽象类中的抽象方法进行覆盖。但是类不能继承多个父类,即正方形不能同时继承图形类与四边形类,这是便产生了接口的概念。简单说,可以通过接口实现多重继承
接口是对抽象类更为细致的划分,一个接口最好只能实现一个功能。抽象类是给同行使用的,接口是给外行使用的
在这里插入图片描述

1.1 抽象类与抽象方法

抽象类声明:
访问修饰符 abstract class 类名:基类或接口
例子:

public  abstract class myclass
        {

        }

抽象方法:
public abstract class myclass
{
public abstract string method(); //抽象方法
}
抽象类与抽象方法注意点:
1.抽象方法只能声明在抽象类中
2.声明抽象方法不能使用virtual、static、private修饰符。如果添加程序会自动报错
3.抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,但承载这个抽象方法的抽象类必须被继承,实际上,抽象类除了被继承之外,没有任何意义。
4.只要类中有一个抽象方法,该类被标记为抽象类
5.当从抽象类派生一个非抽象类时,即继承于父类的子类,是可以被实例化的类。此时需要在非抽象类中重写抽象方法,以提供具体的实现,重写抽象方法时使用关键字override

1.2 抽象类与抽象方法使用实例

public abstract class myClass
    {
        private string id = "";
        private string name = "";
        /// <summary>
        /// 编号属性及实现
        /// </summary>
        public string ID
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }
        /// <summary>
        /// 姓名属性及实现
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        /// <summary>
        /// 抽象方法,用来输出信息
        /// </summary>
        public abstract void ShowInfo();
    }
    public class DriveClass : myClass					//继承抽象类
    {
        /// <summary>
        /// 重写抽象类中输出信息的方法
        /// </summary>
        public override void ShowInfo()
        {
            Console.WriteLine(ID + " " + Name);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            DriveClass driveclass = new DriveClass();		//实例化派生类
            myClass myclass = driveclass;				//使用派生类对象实例化抽象类
            myclass.ID = "BH0001";					//使用抽象类对象访问抽象类中的编号属性
            myclass.Name = "TM";						//使用抽象类对象访问抽象类中的姓名属性
            myclass.ShowInfo();						//使用抽象类对象调用派生类中的方法
            Console.Read();
        }
    }

1.3 接口

接口是抽象类的延伸,可以将它看作是纯粹的抽象类。其定义方法如下:
修饰符 interface 接口名称 :继承的接口列表
{
接口内容;
}
如何理解接口是抽象类的延伸这句话呢?简单说,抽象类A中有3种抽象方法:A1方法、A2方法、A3方法,继承于抽象类A的有2个类:类B、类C,子类类B、类C是需要重写抽象类A的3种方法,类B中恰巧3种方法都需要,可在类B中重写A1、A2、A3方法,但类C中只需要抽象方法A1,重写A1的同时,也要重写A2、A3。这样程序中就会有太多的冗余代码,同时抽象类A的局限性也很大,不需要A2、A3方法的类C也必须重写A2、A3方法。这时,我们可以再定义抽象类D,抽象类A中只包含A1方法,抽象类D中包含A2、A3方法,子类类C可继承抽象A,子类类B需要继承抽象类A和抽象类D,但是一个子类是不能同时继承多个父类接口便能很好的实现这种多重继承
一个类虽然只能继承一个基类,但是可以继承任意接口
接口常见的特征:
1.接口用于描述一组类的公共方法/公共属性
2.接口中的方法没有具体实现,也就是没有方法体,必须由继承者去实现而且必须全部实现。
3. 接口中的方法不需要修饰符,默认就是公有的(Default / Public)
4.接口可以包含方法、属性、索引器、事件。不能包含任何其他的成员,例如:常量、字段、域、构造函数、析构函数、静态成员

1.4 接口使用实例

1.4.1 接口单重继承

以下声明一个接口,接口中包含编号、姓名2个属性,包含一个自定义方法,代码如下:各部分注释已经再代码中体现

interface ImyInterface
    {
        /// <summary>
        /// 编号(可读可写)
        /// </summary>
        string ID       //接口中属性成员是公共的,不需要修饰符
        {
            get;
            set;
        }
        /// <summary>
        /// 姓名(可读可写)
        /// </summary>
        string Name
        {
            get;
            set;
        }
        /// <summary>
        /// 显示定义的编号和姓名
        /// </summary>
        void ShowInfo();    //接口中成员是公共的,不需要修饰符
    }
    class Program : ImyInterface//继承自接口
    {
        string id = "";		//字段
        string name = "";
        /// <summary>
        /// 编号
        /// </summary>
        public string ID
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }
        /// <summary>
        /// 姓名
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        /// <summary>
        /// 显示定义的编号和姓名
        /// </summary>
        public void ShowInfo()		//重写ShowInfo方法
        {
            Console.WriteLine("编号\t 姓名");
            Console.WriteLine(ID + "\t " + Name);
        }
        static void Main(string[] args)
        {
            Program program = new Program();               //实例化Program类对象
            ImyInterface imyinterface = program;           //使用派生类对象实例化接口ImyInterface
            imyinterface.ID = "TM";                        //为派生类中的ID属性赋值
            imyinterface.Name = "C#从入门到精通";  //为派生类中的Name属性赋值
            imyinterface.ShowInfo();                       //调用派生类中方法显示定义的属性值
            Console.Read();
        }
    }

案例分析:继承自接口类class Program,继承了接口ImyInterface的属性和方法,属性定义为公有的,方法重新改写了,主程序中,先实例化类Program,再实例化接口将其与实例化的类绑定,imyinterface.ID、imyinterface.Name、imyinterface.ShowInfo()实际上是实例化类中的参数与方法,类似于委托。

1.4.2 接口多重继承

搞清楚了单重继承的关系,再看多重继承

interface IPeople
    {
        /// <summary>
        /// 姓名
        /// </summary>
        string Name
        {
            get;
            set;
        }
        /// <summary>
        /// 性别
        /// </summary>
        string Sex
        {
            get;
            set;
        }
    }
    interface ITeacher : IPeople            //继承公共接口
    {
        /// <summary>
        /// 教学方法
        /// </summary>
        void teach();
    }
    interface IStudent : IPeople            //继承公共接口
    {
        /// <summary>
        /// 学习方法
        /// </summary>
        void study();
    }
    class Program : IPeople, ITeacher, IStudent//多接口继承
    {
        string name = "";
        string sex = "";
        /// <summary>
        /// 姓名
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        /// <summary>
        /// 性别
        /// </summary>
        public string Sex
        {
            get
            {
                return sex;
            }
            set
            {
                sex = value;
            }
        }
        /// <summary>
        /// 教学方法
        /// </summary>
        public void teach()
        {
            Console.WriteLine(Name + " " + Sex + " 教师");
        }
        /// <summary>
        /// 学习方法
        /// </summary>
        public void study()
        {
            Console.WriteLine(Name + " " + Sex + " 学生");
        }
        static void Main(string[] args)
        {
            Program program = new Program();   //实例化类对象
            ITeacher iteacher = program;       //使用派生类对象实例化接口ITeacher
            iteacher.Name = "TM";
            iteacher.Sex = "男";
            iteacher.teach();
            IStudent istudent = program;       //使用派生类对象实例化接口IStudent
            istudent.Name = "C#";
            istudent.Sex = "男";
            istudent.study();
            Console.Read();
        }
    }

案例分析:多接口继承类Program ,继承了3个接口的属性、方法,并重新写了方法,主函数中的操作于接口中相同。

1.5 抽象类于接口使用情况

1.如果对象存在多个功能相近且关系紧密的版本,则使用抽象类。
2.如果对象关系不密切,但是若干功能拥有共同的声明,则使用接口。
3.抽象类适合于提供丰富功能的场合,接口则更倾向于提供单一的一组功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值