【Unity|C#】基础篇(2)——类(class)

【学习资料】

        > 在线文档

            官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/

            菜鸟教程:https://www.runoob.com/csharp/csharp-tutorial.html

        > 视频教程

            腾讯学院、Siki学院

        > 书籍 

    《C#图解教程》:https://www.cnblogs.com/moonache/p/7687551.html


 【类的特性】

  类的三大特性:封装、继承、多态

    > 封装

      > 访问修饰符

    > 继承

      > 派生子类

      > 构造/析构函数

    > 多态

      > 静态多态性:函数重载(不同参数)、运算符重载

      > 动态多态性:虚函数、抽象函数、隐藏方法

  • 封装

     

  • 继承
    • this   当前类对象
    • base 父类对象
    • sealed密封类,不能被继承
    • sealed class Entity
      {
      }
      class Car : Entity // sealed不能被继承,会报错
      {
      }
    • C#不支持类的多继承,但可以继承多个接口(interface)
    • 构造函数
      • 在创建类对象时,会执行构造函数:Car car = new Car()
      • 构造顺序:调用父类的构造,调用子类
    • 析构函数
      • 在释放对象时(GC垃圾回收),会执行析构函数
      • 析构顺序:调用子类的析构,调用父类
    • class Entity
      {
          // 默认构造函数,无参数
          public Entity()
          {
              Debug.Log("new Entity");
          }
          // 带参构造函数
          public Entity(int id)
          {
              Debug.Log("new Entity id=" + id);
          }
          // 重写析构函数,一个类只能有一个,且无参数
          ~Entity()
          {
              Debug.Log("delete Entity");
          }
      }
      class Car : Entity // sealed不能被继承,会报错
      {
          // 不写父类的构造,默认调用默认构造函数Entity()
          public Car()
          {
              Debug.Log("new Car");
          }
          // 在初始化列表: 调用父类的带参构造函数
          public Car(int id) 
              : base(id)
          {
              Debug.Log("new Car");
          }
          // 重写析构函数,一个类只能有一个,且无参数
          ~Car()
          {
              Debug.Log("delete Car");
          }
      }
  • 多态
    • 静态多态性

      • 函数重载(不同参数)

      • public Tabletop(double l, double w) : base(l, w)
        { }
      • 运算符重载
      • public static Box operator +(Box b, Box c)
        { }
    • 动态多态性:子类重写父类方法
      • 虚函数
        • 关键字:virtual /  override
        • 子类重写虚函数后:不管在父类中调用,还是在子类中调用,执行的都是子类重写后的函数 (Car.Move)
        • 调用父类虚函数的方法:通过 base 关键字调用(base.Move()
        • 注:子类也可不重写父类的虚函数
        • class Entity
          {
              public void AI()
              {
                  Move();
              }
              public virtual void Move() // 虚函数声明 virtual
              {
                  Debug.Log("Entity.Move");
              }
          }
          class Car : Entity
          {
              // 重写方法
              public override void Move() // 重写虚函数 override
              {
                  Debug.Log("Car.Move");
              }
          }

          // 测试Test
          void Start() { Entity entity = new Car(); Car car = (Car)entity; entity.Move(); // 输出:Car.Move car.AI(); // 输出:Car.Move }
      •  抽象函数
        • 关键字:abstract / override
        • 注:父类只声明抽象函数,没有具体实现
        • 注:存在抽象函数的类,必须声明为抽象类,且不能实例化成对象
        • // 含有抽象函数,必须声明为抽象类,且不能实例化对象
          abstract class Entity
          {
              public abstract void Move(); // 抽象函数
          }
          class Car : Entity
          {
              // 子类必须实现父类的抽象函数
              public override void Move()
              {
                  Debug.Log("Car.Move");
              }
          }
          
          void Start()
          {
              // 报错,抽象类无法实例化
              //Entity entity2 = new Entity();
          
              Car entity = new Car();
              entity.Move();  // 输出:Car.Move
          }
      • 隐藏方法 (不推荐,容易出错)
        • 子类重写父类虚函数时,不写 override 关键字编译器也会显示警告(warning)
        • 注:具体执行父类/子类函数,根据调用环境决定(指向对象的引用类型、父类or子类其他函数中进行调用)
        • 测试1:不同引用类型调用Move 、通过AI()函数中调用
          • class Entity
            {
                public void AI()
                {
                    Move();
                }
                public virtual void Move()
                {
                    Debug.Log("Entity.Move");
                }
            }
            class Car : Entity
            {
                // 不写override
                public void Move()
                {
                    Debug.Log("Car.Move");
                }
            }
            
            void Start()
            {
                Entity entity = new Car();
                Car car = (Car)entity;
                entity.Move();  // 输出:Entity.Move
                entity.AI();    // 输出:Entity.Move
                car.Move();     // 输出:Car.Move
                car.AI();       // 输出:Entity.Move
            }
        •  测试2:子类重写AI()函数
          • class Entity
            {
                public virtual void AI()
                {
                    Move();
                }
                public virtual void Move()
                {
                    Debug.Log("Entity.Move");
                }
            }
            class Car : Entity
            {
                public override void AI()
                {
                    Move();
                }
                // 不写override
                public void Move()
                {
                    Debug.Log("Car.Move");
                }
            }
            
            void Start()
            {
                Entity entity = new Car();
                Car car = (Car)entity;
                entity.Move();  // 输出:Entity.Move
                entity.AI();    // 输出:Car.Move
                car.Move();     // 输出:Car.Move
                car.AI();       // 输出:Car.Move
            }

 【接口】 

  > 关键字:interface

  > 相当于是个规则,里面只能有:方法、属性、索引、事件

  > 一个类只能继承一个父类,但可以实现多个接口 

  > 注:接口 也可以 继承另一个 接口

  > 注:一个类继承了接口后,接口中所有的方法(包括属性、索引、事件)都必须实现

  > 注:实现接口中的方法必须定义为 public

    interface EntityInterface
    {
        int Value { get; set; } // 可以声明属性,但子类中必须实现
        void Move();            // 不用写修饰符(public)

        //int value;            // 不能定义变量
        //void AI() { Move(); } // 不能实现接口函数
    }
    class Car : EntityInterface
    {
        // 必须实现接口中的属性,且必须为 public
        public int Value
        {
            get;
            set;
        }
        // 必须实现接口中的函数,且必须为 public
        public void Move()
        {
        }
    }
  • 抽象类(abstract) 与 接口(interface)

    • 抽象类:依然是一个类,不能被实例化,它仍然包含类的函数

    • 接口:相当于是个规则,里面只能有方法、属性、索引、事件

    • 抽象类:有抽象的方法,也有不抽象的方法。子类必须实现父类的抽象方法

    • 接口:继承了接口后,所有的接口方法都必须实现

    • 一个类只能继承一个父类,但是可以实现多个接口

猜你喜欢

转载自www.cnblogs.com/shahdza/p/12235024.html