【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法

文章目录

多态

C# 中的 多态 是面向对象编程中的一个重要特性,允许对象以不同的方式表现出来。通过多态,同一个方法可以根据对象的不同类型而表现出不同的行为。C# 主要通过 方法重载(Overloading)、方法重写(Overriding)和 接口实现 来实现多态。

多态的主要类型

  • 编译时多态静态多态)通过方法重载和运算符重载实现,在编译时就能确定调用哪个方法。
  • 运行时多态动态多态)通过方法重写和接口实现实现,方法的调用是在运行时根据对象的实际类型来决定的。

编译时多态我们已经学过了,就不重复讲了。

一、virtual、override 和 base 关键字

1、virtual 关键字 (虚方法)

virtual 关键字用于在基类中声明一个方法为虚方法。虚方法允许子类在继承时对该方法进行重写(通过 override),从而实现多态。

  • 继承:虚方法通常是在基类中定义的,子类可以继承并对其进行重写。
  • 多态:虚方法支持运行时多态,允许在运行时根据对象的实际类型来调用正确的实现。

示例:

csharp 复制代码
public class Animal
{
    // 基类中的虚方法
    public virtual void Speak()
    {
        Console.WriteLine("Animal speaks");
    }
}

public class Dog : Animal
{
    // 重写基类中的虚方法
    public override void Speak()
    {
        Console.WriteLine("Dog barks");
    }
}

class Program
{
    static void Main()
    {
        Animal animal = new Animal();
        animal.Speak();  // 输出: Animal speaks

        Dog dog = new Dog();
        dog.Speak();     // 输出: Dog barks

        // 多态示例
        Animal animalDog = new Dog();
        animalDog.Speak(); // 输出: Dog barks
    }
}

virtual 的作用

  • virtual 声明基类中的方法为虚方法,子类可以选择是否重写它。
  • 通过虚方法和重写(override),我们实现了 多态

2、override 关键字 (重写)

override 关键字用于在子类中重写基类中的虚方法。它实现了多态机制,允许子类提供不同于基类的具体实现。

  • 继承override 是在子类中对基类方法的实现。
  • 多态 :通过 override,子类改变了基类方法的行为,并且这种改变支持运行时多态。

示例:

csharp 复制代码
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Animal speaks");
    }
}

public class Dog : Animal
{
    public override void Speak()  // 重写基类的虚方法
    {
        Console.WriteLine("Dog barks");
    }
}

class Program
{
    static void Main()
    {
        Animal animal = new Dog();
        animal.Speak();  // 输出: Dog barks (运行时多态)
    }
}

override 的作用

  • override 用于子类中修改继承自基类的虚方法的行为,确保多态性。
  • 它是 多态 实现的一部分,使得在运行时能够调用到正确的方法实现。

3、base 关键字 (基类访问)

base 关键字用于在子类中访问基类的成员(如方法、构造函数等)。在方法重写中,base 可以用于调用基类的方法,通常是在子类重写方法时需要保留基类的一些逻辑。

  • 继承base 允许子类访问基类的方法或字段,这是继承中的一种常见需求。
  • 多态 :虽然 base 本身不直接表示多态,但它通常在重写方法时与多态一起使用,确保子类能够在需要时调用基类的方法。

示例:

csharp 复制代码
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Animal speaks");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        base.Speak();  // 调用基类的 Speak 方法
        Console.WriteLine("Dog barks");
    }
}

class Program
{
    static void Main()
    {
        Animal animal = new Dog();
        animal.Speak();
    }
}

base 的作用

  • base 允许子类在重写方法时调用基类的方法,这通常用于在重写时保留基类的行为。
  • 它本身不直接影响多态性,但它可以与多态一起使用,以确保基类方法能够在子类中被访问。

4、总结:

  • virtual 关键字与 继承 相关,允许基类中的方法在子类中被重写,从而为 多态 打下基础。
  • override 关键字用于在子类中重写基类中的虚方法,是实现 多态 的关键。
  • base 关键字用于子类访问基类的成员,它与 继承 关系更为紧密,但在重写方法时也常常与 多态 结合使用。

二、抽象类和抽象方法

在 C# 中,抽象类抽象方法(函数)是面向对象编程中的核心概念,旨在提供一种模板或基础结构,供子类继承并实现细节。它们在定义类的层次结构和实现多态性方面发挥着重要作用。

1、抽象类

1.1 什么是抽象类

抽象类是不能实例化的类,它提供了一个通用的类模板,不能直接创建其对象。抽象类可以包含抽象方法和普通方法,也可以包含字段和属性。

  • 抽象类通常是作为基类(父类)来提供子类继承。
  • 抽象类可以包含 抽象方法 (没有方法体,需要由子类实现),也可以包含 具体方法(已经实现的方法,子类可以直接使用或重写)。

1.2 定义和使用抽象类

  • 抽象类使用 abstract 关键字声明。
  • 抽象类可以有构造函数,但不能直接实例化。
csharp 复制代码
using System;

abstract class Animal
{
    public string Name { get; set; }

    // 抽象方法:没有实现,要求子类必须实现
    public abstract void Speak();

    // 普通方法:可以直接使用或重写
    public void Eat()
    {
        Console.WriteLine($"{Name} is eating.");
    }
}

class Dog : Animal
{
    public Dog(string name)
    {
        Name = name;
    }

    // 必须实现抽象方法
    public override void Speak()
    {
        Console.WriteLine($"{Name} barks.");
    }
}

class Program
{
    static void Main()
    {
        // Animal animal = new Animal(); // 错误,不能直接实例化抽象类
        Dog dog = new Dog("Buddy");
        dog.Speak();  // 输出:Buddy barks.
        dog.Eat();    // 输出:Buddy is eating.
    }
}

在这个例子中,Animal 是一个抽象类,它包含一个抽象方法 Speak 和一个普通方法 Eat。类 Dog 继承自 Animal 并实现了 Speak 方法。

2、抽象方法

2.1 什么是抽象方法

抽象方法是没有实现的方法,只有方法签名。它们必须在抽象类中定义,并且在任何非抽象的子类中实现。抽象方法提供了一个接口或契约,要求派生类必须提供该方法的具体实现。

  • 抽象方法使用 abstract 关键字声明。
  • 抽象方法不能包含方法体,只有方法签名。
  • 抽象方法必须在子类中重写(通过 override 关键字实现)。

2.2 定义和使用抽象方法

csharp 复制代码
abstract class Shape
{
    // 抽象方法:每个子类需要实现自己的计算面积方法
    public abstract double Area();
}

class Circle : Shape
{
    public double Radius { get; set; }

    public Circle(double radius)
    {
        Radius = radius;
    }

    // 实现抽象方法
    public override double Area()
    {
        return Math.PI * Radius * Radius;
    }
}

class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    // 实现抽象方法
    public override double Area()
    {
        return Width * Height;
    }
}

class Program
{
    static void Main()
    {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(10, 20);

        Console.WriteLine($"Circle Area: {circle.Area()}");
        Console.WriteLine($"Rectangle Area: {rectangle.Area()}");
    }
}

在这个例子中,Shape 是一个抽象类,包含一个抽象方法 Area,它在 CircleRectangle 类中被具体实现。这是一个常见的场景:抽象类提供了一个通用的接口(如 Area),具体的计算方法由子类来实现。

3、抽象类和抽象方法的特点

  1. 抽象类不能实例化:不能直接创建抽象类的对象,必须通过子类来实例化。

  2. 抽象方法没有方法体:抽象方法只定义方法签名,子类必须提供实现。

  3. 可以包含普通方法:抽象类除了抽象方法外,还可以包含已经实现的普通方法、字段、属性和构造函数。

  4. 子类实现抽象方法:任何继承抽象类的子类,必须实现所有的抽象方法,否则该子类也必须被声明为抽象类。

  5. 构造函数:抽象类可以有构造函数,可以在子类中调用基类构造函数来初始化。

  6. 多态性:通过抽象类和抽象方法,可以在子类中提供不同的实现方式,利用多态性让代码更加灵活。

4、使用抽象类和抽象方法的优势

  1. 代码复用:抽象类允许在基类中实现一些公共的功能或模板方法,避免重复代码。
  2. 强制实现契约:通过抽象方法,确保所有子类都遵守同一个方法签名和行为规范,保证了接口的一致性。
  3. 多态性:抽象类提供了通过基类引用调用子类实现的多态性,使得代码更加灵活和扩展性更强。

5、小结

  • 抽象类 是一个不能实例化的类,它提供了一个通用的模板,供其他类继承。
  • 抽象方法 是没有方法体的方法,它定义了一个接口,强制派生类实现具体的功能。
  • 抽象类和抽象方法是面向对象设计中非常重要的工具,能够提高代码的可维护性和可扩展性。

专栏推荐

地址
【从零开始入门unity游戏开发之------C#篇】
【从零开始入门unity游戏开发之------unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

相关推荐
2401_857439699 分钟前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna38 分钟前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_43 分钟前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
异次元的归来2 小时前
Unity DOTS中的share component
unity·游戏引擎
Dream_Snowar2 小时前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫2 小时前
泛型(2)
java
超爱吃士力架2 小时前
邀请逻辑
java·linux·后端
南宫生2 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论