C#虚方法、隐藏方法、抽象类、抽象方法、 接口

1.虚方法与隐藏方法

    什么是虚方法?

    简单的说,虚方法就是可以被子类重写的方法,如果子类重写了虚方法,那么运行时将使用重写后的逻辑,如果没有重写,则使用父类中虚方法的逻辑。

 class Enemy
 {
  public virtual void Attack()
  {
        Console.WriteLine("Enemy Attack");
  }

 }

 class Zombie : Enemy
 {
     public override void Attack()
     {
         Console.WriteLine("Zombie Attack");
     }
 }

       上面的代码中Enemy类中拥有一个Attack方法,该方法被virtual关键字修饰,它就是虚方法。

       关于虚方法的定义我们提到了虚方法是可以被子类重写的,我们可以看到Zombie类是Enemy类的子类,它也拥有一个Attack方法,Zombie类的Attack方法被override关键字修饰,重写了从父类继承下来的Attack方法(所以Zombie类Attack方法的运行结果会是Zombie Attack而不是Enemy Attack)。

       在这里很多人可能会困惑,如果我这样写代码是不是也是使用了虚方法呢?

 class Enemy
 {
  public  void Attack()
  {
        Console.WriteLine("Enemy Attack");
  }

 }

 class Zombie : Enemy
 {
     public void Attack()
     {
         Console.WriteLine("Zombie Attack");
     }
 }

     这并没有使用虚方法,而是Zombie子类隐藏了父类的Attack方法。我们首先明确一个概念,隐藏方法只是隐藏了父类的方法,并没有重写父类的方法,在后面的代码验证中我们能清晰的体会到这一点。

     那隐藏方法和虚方法的区别在哪呢?

    static void Main(string[] args)
    {
        Zombie zombie = new Zombie();//创建一个Zombie类实例
        Enemy enemy1 = new Enemy();//创建一个Enemy类实例
        Enemy enemy2 = new Zombie();//多态 通过Enemy父类创建一个Zombie子类实例(父类引用指向子类实例)
        zombie.Attack();
        enemy1.Attack();
        enemy2.Attack();
        Console.ReadLine();
    }
}
class Enemy
{
 public virtual void Attack()
 {
       Console.WriteLine("Enemy Attack");
 }

}

class Zombie : Enemy
{
    public override void Attack()
    {
        Console.WriteLine("Zombie Attack");
    }
}

       我们来看看运行结果

  

       可以看到我们通过Enemy父类创建出来的Zombie子类实例执行的是子类实例重写过的Attack方法(Zombie Attack)。

       如果我们将刚才的代码中的Virtual关键字与override关键字删去,那就变成了隐藏方法,Zombie子类隐藏的父类Enemy类中的Attack方法,我们来看看运行结果。

    

      我们可以看到,我们通过Enemy父类创建出来的Zombie子类实例执行的是父类的Attack方法,我们来做个总结。     

     重写时,定义的变量为父类或子类, 创建为子类时.  皆调用子类的重写方法;

     隐藏时,定义的变量为父类则调用父类的方法(不管赋值是子类还是父类),创建为子类则调用子类的方法。

2.抽象类与抽象方法

     什么是抽象方法?只有声明,没有实现的方法就是抽象方法。下面的Attack方法就是一个抽象方法,我们可以看到它被abstract关键字修饰,且没有方法体(没有实现)。如果一个类中拥有一个抽象方法,那么这个类也需要被abstract关键字修饰(该类就为一个抽象类)。

     抽象方法:必须要被重写(抽象方法是更加抽象的虚方法,没有方法体)

     虚方法:可以重写也可以不重写(因为虚方法自身就有方法体)

     注意,抽象类不能被实例化,继承了抽象类的子类必须要实现抽象类中的方法。

  abstract class Enemy
  {
      public abstract void Attack(); 
  }

         我们为什么要使用抽象方法与抽象类?如果我们要做一个勇士打怪物的游戏,我们需要创建很多的怪物,僵尸,骷髅等。他们都属于敌人。那敌人就可以被抽象为一个抽象类(很显然敌人一定是拥有攻击和移动这两种行为的)。我们在创建之后的僵尸与骷髅类时只需要继承敌人这个抽象类,并且实现敌人这个抽象类中的方法就可以了。

        我们为什么不使用虚方法而使用抽象方法呢?在这个例子中敌人这个类太笼统,我们不需要使用Enemy Attack这个笼统的攻击方法(因为我们根本不知道是谁在Attack),所以我们干脆就让Attack方法更加的抽象(虚方法更抽象就变成了抽象方法),这个方法不需要方法体,只需要让别人知道敌人拥有Attack这个方法,至于这个Attack方法是什么样的,交给继承该抽象方法的子类去处理,就如我们下边例子中Zombie的Attack方法,就是对Enemy类中抽象的Attack方法的实现。(注意,我们实现抽象方法需要使用Override关键字)。

    static void Main(string[] args)
    {
        Zombie zombie = new Zombie();
        Skeleton skeleton = new Skeleton(); 
        zombie.Attack();
        zombie.Move();
        skeleton.Attack();
        skeleton.Move();
        Console.ReadLine();
    }
}
abstract class Enemy//抽象类
{
    
    public abstract void Attack();//抽象方法
    public abstract void Move();//抽象方法
}

class Zombie : Enemy
{
    public override void Attack()//实现抽象方法Attack
    {
        Console.WriteLine("Zombie Attack");
    }

    public override void Move()//实现抽象方法Move
    {
        Console.WriteLine("pu pu pu");
    }
}
class Skeleton : Enemy
{
    public override void Attack()
    {
        Console.WriteLine("Skeleton Attack");
    }

    public override void Move()
    {
        Console.WriteLine("ka ka ka");
    }
}

  

3.接口

     什么是接口? 我们先来看看接口的使用,你会发现接口与抽象类很相似,我们在看完接口的使用以后再来详细讲解接口

    interface IEnemy
    {
         void Attack();
         void Move();
    }
class Zombie : IEnemy//Zombie类继承了IEnemy这个接口
{                    //继承接口就必须实现被继承接口的所有方法
    public  void Attack()//实现Attack方法
    {
        Console.WriteLine("Zombie Attack");
    }

    public  void Move()//实现Move方法
    {
        Console.WriteLine("pu pu pu");
    }
}
class Skeleton : IEnemy
{
    public  void Attack()
    {
        Console.WriteLine("Skeleton Attack");
    }

    public  void Move()
    {
        Console.WriteLine("ka ka ka");
    }
}

     我们发现,接口与抽象类是如此的相似,我们对比IEnemy(接口的命名通常会在最前面加一个I)接口与Enemy类。

     IEnemy被Interface修饰,Enemy抽象类被Class关键字和abstract关键字修饰

     IEnemy接口中的方法无Public访问修饰符(接口中的所有方法默认且只能为public)

     类继承接口中的方法,且要实现这些继承自接口的方法时无需使用override关键字。

     抽象类与接口一样,被继承就要实现所有被继承的方法。

     类是单继承的,而接口是多继承的!

 4.一个关于使用接口或是抽象类的简单例子

      我们从一个例子去体会如何选择使用接口与抽象类。

      我们这样思考,一个勇士打怪物的游戏,除了怪物会被攻击以外,勇士也可以破坏门,所以不只是怪物会拥有一个受到攻击的方法,如果我们将受击方法写入Enemy类中,我们的门是不能去继承Enemy类的(门又不能攻击和移动),所以我们将TakeHit方法抽象出来,写入到IDamageable接口中去,这样我们的Enemy类和Door类都可以去继承IDamageable这个接口,从而都能实现TakeHit这个方法。

   interface IDamageable     //为什么创建IDamageable接口
   {
       void TakeHit();//受击方法 
   }
   class Door : IDamageable  //在游戏中不只是Enemy类会被攻击, 门也可以被破坏
   {
       public void TakeHit()
       {
           //dosomething
       }
   }

   public abstract class Enemy : IDamageable
   {

       public abstract void Attack();
       public abstract void Move();
       public abstract void TakeHit();
   }
       class Zombie : Enemy
       {

           public override void Attack()
           {
               Console.WriteLine("Zombie Attack");
           }

           public override void Move()
           {
               Console.WriteLine("pu pu pu");
           }

       public override void TakeHit()
       {
           //dosomething
       }
   }
       class Skeleton : Enemy
       {

           public override void Attack()
           {
               Console.WriteLine("Skeleton Attack");
           }

           public override void Move()
           {
               Console.WriteLine("ka ka ka");
           }

       public override void TakeHit()
       {
           //dosomething
       }
   }  

5.总结

       借用刘铁猛老师C#视频教程中的一张图作一个总结以及结尾!

       这是我对B站Up主TimothyLiu(刘铁猛老师!!!)对于虚方法,抽象方法,接口的学习总结,如有错漏,恳请指出,谢谢!

  • 34
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值