C#抽象类和接口之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于抽象类和接口的选择显得比较随意。其实,两者之间还是有很大的区别的。首先,以抽象类的方式定义一个公共的抽象类Animal如下:

public abstract class Animal   
{
    public abstract void Run();
    public abstract void Eat();
}

注意:类中默认的范围是private, 一定要显式将抽象的内容显示声明为public

然后使用接口的方式定义接口Animal如下:

public interface IAnimal
{
    abstract void Run();
    abstract void Eat();
}

注意:虽然在.NET中不再主张匈牙利命名法,但是在使用接口的时候还是习惯上加上大写字母“I”以表示接口。

抽象类和接口的相同点:

1)都是通过继承实现,而不能直接实例化,
如:Animal animal = new Animal();                         //错误!
或者:IAnimal animal = new IAnimal();                       //错误!

抽象类和接口通过关键字new实例化都是错误的!!

注意:这里要说明一点,任何接口都是不可能实例化的,除了抽象类,一般的类都是可以实例化,而且如果可以实例化,那么它一定是一个非抽象类。

2)都有没有实现的抽象方法,抽象方法仅仅是一个对方法的定义并没有具体的实现,只有在派生的使用override进行重写才能得到实现。
如下面所示:Animal和IAnimal都定义了的两个方法Run()和Eat()
   
abstract void Run();
abstract void Eat();

它们并没有实现真正的内容,你并不知道Run或者Eat到底是怎么Run或者Eat的,只是知道这两个函数的存在,定义存在的作用在于,只要定义了那么虽然不知道怎么实现,但是可以确定这两个方法对于一般Animal来说都应该是存在的,派生的时候才会根据不同的派生类的特点实现所需要的功能,从而也完成了多态的实现,同时要注意一点,如果存在这样的的情况,比如Run对鸟类可能不实用,同时Fly对于陆地的动物也一样不存在,多态的实现办法是不处理,而不处理本身也是多态。

下面我们以Animal和IAnimal为基础,分别以抽象类和接口的方式派生出 一个DOG类。
代码如下:    
    public abstract class Dog : Animal       //从Animal类派生出Dog类
    {
        override void Run()
        {
            Console.WriteLine("Dog runs.");
        }
        override void Eat()
        {
            Console.WriteLine("Dog eat.");
        }
    }
      //从IAnimal接口派生出Dog类
      public abstract class Dog : IAnimal
    {
        override void Run()
        {
            Console.WriteLine("Dog runs.");
        }
        override void Eat()
        {
            Console.WriteLine("Dog eat.");
        }
   }

我们从上面可以看出,实现的方法是完全一样的,没有什么区别。

接口和抽象类的区别:

共同点是比较容易理解的,但是两者的区别更是要知道,下面把两者的区别先列出来,然后举例说明:
1)接口支持多继承,抽象类不能实现多继承;

public interface IEat
    {
        abstract void Eat();
    }
    public interface IRun
    {
        abstract void Run();
    }
    public class Dog : IEat, IRun
    {        …
    }

以上实现了IEat和IRun两个接口,在Dog类派生时实现。

2)接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员,下面的Eat就得到了实现,只有类可以实现。
public abstract class Animal
{
     abstract void Run();
     public void Eat()
     {
         Console.WriteLine("Animal Eat.");
     }
}

3)接口是一组行为规范,只提供方法,主要强调方法重写(override)的概念,可以理解为一个不完全的类,而抽象类中还可以有属性,事件等内容,同时既可以有初值也可以完全抽象。

4)接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。

public abstract class Animal
    {
        string animalName;
        //非抽象属性
        public string AnimalName
        {
            get { return animalName; }
            set { animalName = value; }
        }
           //抽象属性
        public abstract float Weight
        {
            get;
            set;
        }
        public abstract void Run();
        public void Eat()
        {
            Console.WriteLine("Animal Eat.");
        }
    }

5) 接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。

总结:

应该说,接口的使用面比抽象类更广一些,而抽象类比接口更具限制性,但是功能上更加强大,体现的是继承关系。当类的发展不需要受到限制和约束时,我们可以使用接口,此类可以自由的发展,此时继承接口的这个类就是一个稳定的类,这也体现了接口保持类的稳定性。这两者具备有很大的相似性,都源于面向对象思想,在使用何时抽象类,何时接口并没有一个定论,应该根据自己程序的大小、设计的方式、程序发展的空间来看,这就需要扎实的理论基础和大量的实践经验了。

C#类、接口、虚方法和抽象方法-抽象类与接口的区别与联系相关推荐

  1. C#类、接口、虚方法和抽象方法-虚拟方法与抽象方法之区别

    虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢? 1. 虚方法必须有实现部分,并为派生类提供了重写该方法的选项.抽象方法没有提供实现部分,抽象方法是一种强制派生类重写的方法,否则派生类将不能 ...

  2. C#类、接口、虚方法和抽象方法

    C#类.接口.虚方法和抽象方法 虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢? 1. 虚方法必须有实现部分,并为派生类提供了重写该方法的选项.抽象方法没有提供实现部分,抽象方法是一种强制派 ...

  3. 理解 Delphi 的类(十一) - 深入类中的方法[8] - 抽象方法与抽象类

    //抽象方法类似与接口; 在没有接口的年代 Delphi 是用抽象方法来模拟接口的; 我想它最终会被接口替代.{下面就定义了两个抽象方法} TMyClass = class(TObject)proce ...

  4. java虚方法和抽象方法_虚方法和抽象方法--基础回顾

    抽象方法是只有定义.没有实际方法体的函数,它只能在抽象函数中出现,并且在子类中必须重写:虚方法则有自己的函数体,已经提供了函数实现,但是允许在子类中重写或覆盖. 重写的子类虚函数就是被覆盖了. 抽象方 ...

  5. 重写方法,重载方法,虚方法和抽象方法的使用

    重写方法,重载方法,虚方法和抽象方法. 重写:指子类重新实现父类的某些方法,以实现一些新的功能.重写的关键字是override.并且重写的方法其签名是相同的. 重载:指允许类中具有相同函数名的方法,但 ...

  6. 虚方法和抽象方法的区别

    在查阅资料的过程中,偶然看到了虚方法和抽象方法,对其做个小结. 对比学习: 虚方法必须有实现部分,抽象方法不可以有实现部分: 虚方法可以在派生类中重写也可以不重写,抽象方法必须在派生类中重写: 虚方法 ...

  7. C#~虚方法,虚方法和抽象方法的区别

    虚方法 特点: <1>虚方法必须使用virtual修饰 <2>虚方法同抽象方法(adstract)一样使用override关键字重写 <3>虚方法在子类中可以实现, ...

  8. LindAgile~缓存拦截器支持类的虚方法了

    写它的原因 之前写过一个缓存拦截器,主要在方法上添加CachingAspect特性之后,它的返回值就可以被缓存下来,下次访问时直接从缓存中返回结果,而它有一个前提,就是你的方法需要是一个接口方法,缓存 ...

  9. SV 类的虚方法 多态

    SV 类的虚方法 多态 类型转换 概述 概述 类的成员方法可以加修饰词virtual(虚方法) 虚方法是一种基本的多态结构 一个虚方法可以覆盖基类的同名方法 在父类和子类中声明虚方法,其方法名.参数名 ...

最新文章

  1. 5-35 城市间紧急救援 (25分) pat 数据结构
  2. Springboot使用Log4j2的配置详解
  3. 金融业如何更好地利用大数据实现突破性变革?(实例解读)
  4. FTP服务器配置与管理(4) 服务器端的常用配置及FTP命令
  5. [AtCoder Grand Contest 048] D - Pocky Game(区间dp + 博弈)
  6. 中医教你5个补肾护发食疗方
  7. GoogLeNet——CNN经典网络模型详解(pytorch实现)
  8. 连接oracle出现ORA-12514错误
  9. group by having where order by
  10. 2017微软校园招聘笔试题
  11. 从0到1,用张三的故事讲述一张中学生也能看懂的财务报表
  12. vue xlsx插件导入
  13. 痘痘告诉你,身体哪里生病了
  14. 高配云计算机平台,云电脑真的来了!小破本也能秒变高配
  15. halcon_halcon图像处理基本运算
  16. 用keil语言定义c51,51单片机Keil C51的使用(C语言)
  17. 【优化求解】基于蝗虫算法(MOGOA)求解多目标问题matlab源码
  18. 深入理解JVM:java对象的创建过程?
  19. 【计算机科学速成课】[40集全/文字版] - 1.计算机的早期历史
  20. 我的世界服务器怎么设置自动拾取,我的世界自动拾取mod

热门文章

  1. 【操作系统】哲学家就餐问题
  2. leetcode验证冒泡排序效率
  3. node.js async await 配合Promise对象使用
  4. shell编程题(二)
  5. 【树】104. 二叉树的最大深度
  6. 103. 二叉树的锯齿形层次遍历
  7. 主成分分析(PCA)原理详解_转载
  8. day03 基本数据类型
  9. mysql.sock问题
  10. Jenkins连接TFS出现错误:“jenkins com.microsoft.tfs.core.exceptions.TECoreException”的问题收集...