1.多态 vob

        1.基本概念:

                字面意思就是多种状态,让继承同一个父类的子类们,在执行相同方法时,有不同的表现,产生不同的结果。

                vob:

                        v: virtual (虚函数)

                        o: override (重写)

                        b: base (父类)

2.虚函数(virtual)

        1.基本概念:

                使用 virtual关键字声明的方法 。​​虚函数不重写时,会自动执行基类中的实现

                注意:virtual关键字应该放在​​返回类型(void)之前

class GameObject
{
    public string name;
    
    public GameObject(string name)
    {
        this.name = name;
    }
    
    // 虚函数
    public virtual void Atk()
    {
        
    }
}

GameObject obj = new GameObject("Enemy");
obj.Atk();  // ✅ 可以调用

 3.重写(override)

        1.基本概念:

                方法重写​​指的是在派生类中重新定义基类中已存在的虚方法、抽象方法或已重写方法,以改变方法的行为。

        2.重写规则

                1.必须使用override关键字​

                ​​2.基类方法必须标记为virtualabstractoverride

                3.访问修饰符必须相同​

                4.方法签名必须完全一致​​(名称、参数、返回类型)

class GameObject
{
    public string name;

    public GameObject(string name)
    {
        this.name = name;
    }
    
    // 虚函数
    public virtual void Atk()
    {
        Console.WriteLine("攻击");
    }
}


class Player: GameObject
{
    public int age;
    public Player(string name, int value): base(name)
    {
        age = value;
    }

    // 重写
    public override void Atk()
    {
        Console.WriteLine("玩家攻击");
    }
}

class Boss:GameObject
{
    public Boss(string name): base(name)
    {
    
    }

    
    public override void Atk()
    {
        // base的作用:通过base来保留父类的行为
        base.Atk(); // 先调用基类(GameObject)的Atk()
        Console.WriteLine("Boss攻击"); // 再执行Boss特有的逻辑
    }
}


GameObject object = new Player("张三",18);
object.Atk(); // 输出:玩家攻击


GameObject boss = new Boss("哥布林");
boss.Atk(); // 输出:攻击
           //       哥布林攻击

        3.重写和重载

                1.重写是子类重重新定义父类的虚方法/抽象方法;是运行时多态;需使用virtual关键字;方法签名(名称、参数、返回类型)必须完全一,访问修饰符不能更严格(访问范围可以变大,不能变小)

                2.重载是在同一个类中,多个同名方法;是编译时多态;函数名相同,参数和返回值可以不相同,访问修饰符也可以不同

// 重写
class GameObject
{
    public string name;
    
    public GameObject(string name)
    {
        this.name = name;
    }

    // 虚方法
    public virtual void Atk()
    {

    }
}


class Player:GameObject
{
    public Player(string name):base(name)
    {
    
    }

    // 重写
    public override void Atk()
    {

    }

}



// 重载
class Calculator
{
    // 方法重载
    public int Add(int a, int b) => a + b;
    
    public double Add(double a, double b) => a + b;
    
    public string Add(string a, string b) => a + b;
    
    public int Add(int a, int b, int c) => a + b + c;
}

4.抽象类和抽象函数

        1.抽象类基本概念

                关键字:abstract

··              抽象类它不能被实例化,只能作为基类被继承。

                注意:继承抽象类,必须重写其抽象方法。

        2.抽象方法基本概念

                抽象方法 abstract 关键字修饰的方法,必须声明在抽象类中。不能有方法体(没有{}

                注意:​​当一个非抽象类继承自抽象类时,它必须实现该抽象类中的所有抽象成员(包括抽象方法和抽象属性)​​。

// 抽象类
public abstract class Person
{
   // 抽象成员属性
   public abstract string Name{get;}; 

   // 抽象方法
    public abstract void Atk();
}

public class Player: Person
{
    // 重写抽象属性
    public override string Name => "张三"; 
    // 等价于 public override string Name {grt{return "张三";}}

    // 重写抽象方法
    public override void Atk()
    {
        Console.WriteLine("攻击");
    }
}

        4.如何选择抽象类和普通类

                不希望被实例化的对象,相对比较抽象的对象可以使用抽象类(比如:动物、植物、怪物等等),我们可以将这这一类对象共有的特性写在抽象类中。

                父类中的行为不太需要被实现的,只想子类去定义具体的规则,可以选择抽象类然后使用其中的抽象函数来定义规则。

5.接口

        1.基本概念

                接口是一种完全抽象的类型,只包含成员声明而不包含实现。一个类可以有多个接口

                关键字:interface

        2.接口的声明规范

                1.接口不能包含成员变量,只能包含方法、属性、索引器、事件

                2.成员不能被实现,不能有方法体(没有{})

                3.​接口成员默认是public的​​,成员可以不用写访问修饰符,不能私有化的

                4.接口不能继承类,但是可以继承接口

                5.类继承接口后,必须实例化接口中的所有成员

        3.接口的声明

interface 接口名
{

}

// 接口的声明
public interface IAnimal
{
    string Name { get; }        // 属性声明
    void MakeSound();           // 方法声明
    event Action OnMove;        // 事件声明
}


// 接口实现
public class Dog : IAnimal
{
    public string Name => "Dog";
    
    public void MakeSound()
    {
        Console.WriteLine("Woof!");
    }
    
    public event Action OnMove;
}

        4.多接口实现

public interface IAnimal
{
    string Name { get; }        // 属性声明
    void MakeSound();           // 方法声明
    event Action OnMove;        // 事件声明
}

public interface IFlyable
{
    void Fly();
}

public interface ISwimmable
{
    void Swim();
}


// 多接口实现
public class Duck : IAnimal, IFlyable, ISwimmable
{
    public string Name => "Duck";
    
    public void MakeSound() => Console.WriteLine("Quack!");
    public void Fly() => Console.WriteLine("Duck flying");
    public void Swim() => Console.WriteLine("Duck swimming");
    public event Action OnMove;
}

6.其他

        1.命名空间

                (1)概念:命名空间是一种组织代码的方式,它允许开发者将一组相关的对象放在一个命名的作用域内。这样做的主要目的是为了避免不同库或应用程序中的名称冲突,类似于现实生活中文件夹的概念,不同的文件夹可以包含相同名称的文件,而不会产生混淆。

                (2)语法:

namespace 命名空间名称
{
    类
    类
}


// 命名空间可以分开写
namespace MyGame
{
    class GameObject
    {

    }
}

namespace MyGame
{
    class Player: GameObject
    {

    }
}

                 (3) 命名空间的使用 

                        1.不同命名空间中相互引用,需要引用命名空间或者指明出处(也就是不同脚本之间的引用)Unity中可能有所不同。

                        2.命名空间可以嵌套命名空间(可以理解从工具包中的小工具包)

                                法一:

                                        using 命名空间名称

                               法二:

                                        命名空间名称.类名

                                        命名空间名称1.命名空间名称2.类名(嵌套命名空间)

                        注意:如果在同一个命名空间里,使用不同命名空间的同名类需要指出命名空间

        2.万物之父(object)中的方法

                (1)object中的静态方法

                        Equals()  判断两个对象是否相等。不管是值类型还是引用类型都可以利用Equals()方法来比较

class Boss
{

}

class Player
{

}


Boss boss1 = new Boss();
Boss boss2 = new Boss();

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐