【学习资料】

  《C#图解教程》(第4~7章):https://www.cnblogs.com/moonache/p/7687551.html
  电子书下载:https://pan.baidu.com/s/1mhOmBG0

【内容】

    • 所有类的基类
    • 类的组成
    • 类的实例化、内存分配
    • 类的特性:封装、继承、多态
    • 接口
    • 扩展知识
      • 隐藏基类的成员
      • struct、class
      • 抽象函数(abstract)、虚函数(virtual)
      • 抽象类(abstract)、接口(interface)

【笔记】

  所有类的基类: object 

  类由2部分组成

    > 数据成员:存储与类或类的实例相关的数据
    > 函数成员:执行代码

      

  类的实例化

    > 声明一个类的引用,指向空数据null

      

    > new数据部分,并将引用指向数据

      


【类的特性】

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

    > 封装

      > 访问修饰符

    > 继承

      > 派生子类

      > 构造/析构函数

    > 多态

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

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

  • 封装

    

  • 继承

    • this   当前类对象
    • base : 父类对象
    • sealed密封类,不能被继承
    • sealed class Entity
      {
      }
      class Car : Entity // sealed不能被继承,会报错
      {
      }
    • C#不支持类的多继承,但可以继承多个接口(interface)
    • 父类初始化:在初始化列表里进行
    • public Tabletop(double l, double w) : base(l, w)
      { }
    • 构造函数
      • 在创建类对象时,会执行构造函数: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()
{
}
}

【扩展知识】

  • 隐藏基类的成员

    • 子类通过new关键字,隐藏父类的成员数据、方法
    • 具体调用的是哪个?根据调用环境决定(指向对象的引用类型、父类or子类其他函数中进行调用)

        

    • 案例1:不同引用类型获取.value、调用父类的PrintValue

      • class A
        {
        public int value = ;
        public void PrintValue()
        {
        Debug.Log("A.value=" + value);
        }
        }
        class B : A
        {
        public new int value = ;
        }
        void Start()
        {
        A a = new B();
        B b = (B)a;
        Debug.Log(a.value); // 1
        Debug.Log(b.value); // 2
        a.PrintValue(); // A.value=1
        b.PrintValue(); // A.value=1
        }
    • 案例2:子类隐藏父类的PrintValue
      • class A
        {
        public int value = ;
        public void PrintValue()
        {
        Debug.Log("A.value=" + value);
        }
        }
        class B : A
        {
        public new int value = ;
        // 隐藏父类函数
        public new void PrintValue()
        {
        Debug.Log("B.value=" + value);
        }
        }
        void Start()
        {
        A a = new B();
        B b = (B)a;
        a.PrintValue(); // A.value=1
        b.PrintValue(); // B.value=2
        }
    • 案例3:子类重写父类的PrintValue
      • class A
        {
        public int value = ;
        public virtual void PrintValue()
        {
        Debug.Log("A.value=" + value);
        }
        }
        class B : A
        {
        public new int value = ;
        // 重写父类函数
        public override void PrintValue()
        {
        Debug.Log("B.value=" + value);
        }
        }
        void Start()
        {
        A a = new B();
        B b = (B)a;
        a.PrintValue(); // B.value=2
        b.PrintValue(); // B.value=2
  • struct 、class

    • 类 是 引用类型,结构体 是 值类型

    • 因此结构体不能=null,也不需要使用new

    • 结构体 不支持继承

    • 结构体 不能声明 默认(无参)构造函数,不能声明 析构函数

    • 结构体成员 不能指定为 abstract、virtual 或 protected

 

  • 抽象函数(abstract) 、虚函数(virtual)

    • abstract:父类只声明没有具体实现,子类必须重写实现父类中的抽象函数

    • virtual:子类可以不重写父类的虚函数

 

  • 抽象类(abstract) 、接口(interface)

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

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

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

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

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

【Unity|C#】基础篇(3)——类(class)/ 接口(interface)的更多相关文章

  1. 新年在家学java之基础篇-高级类的特性

    继承 extends 子类的共性代码都是继承自父类的,每个子类只要写自己特有的代码 class 子类 extends 父类 继承提高了代码的复用性,提供了多态的前提,但是不要为了某个功能去继承 子类不 ...

  2. 线程基础知识01-Thread类,Runnable接口

    常见面试题:创建一个线程的常用方法有哪些?Thread创建线程和Runnable创建线程有什么区别? 答案通常集中在,继承类和实现接口的差别上面: 如果深入问一些问题:1.要执行的任务写在run()方 ...

  3. C#基础篇七类和静态成员

    1.new关键字做的4个事情 1.1 开辟堆空间 a.开辟多大的空间呢? 当前类 所有的 成员变量类型所占空间的总和 + 类型指针(方法表的地址) b.开辟了空间干什么用呢? 存放 成员变量 1.2 ...

  4. JAVA基础篇 之 类的初始化

    类中属性的隐式初始化,代码如下,我们看下不同类型默认的初始值是什么 创建一个Demo类如下: class Demo { int a; byte b; short c; long d; boolean ...

  5. 【Java_多线程并发编程】基础篇—Thread类中start()和run()方法的区别

    1. start() 和 run()的区别说明 start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用. run()方法 ...

  6. C# 类(9) - 接口 Interface

    Interface 接口 类似 抽象类,也不能被实例化...(前面说的静态类,加上抽象类,还有这个,都3个了)接口其实比 抽象类 更加抽象.接口的方法(这个方法还不能有实体代码,和抽象类的抽象方法差不 ...

  7. 图解Python 【第五篇】:面向对象-类-初级基础篇

    由于类的内容比较多,分为类-初级基础篇和类-进阶篇 类的内容总览图: 本节主要讲基础和面向对象的特性 本节内容一览图: 前言总结介绍: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 ...

  8. cocos2dx基础篇(3) 常用重要类

    ---------------------------------------- 入口类main.cpp 主要控制类AppDelegate.cpp -------------------------- ...

  9. Hibernate.基础篇《一》.Hibernate工具类.

    Hibernate.基础篇<一>.Hibernate工具类. 话述: Hibernate.基础篇第一篇,前面是代码.后面再加理论&实践. Hibernate使用的版本是:5.x,在 ...

随机推荐

  1. Ant Design 方法默认传值,加上其他参数

    前端填坑之路Ant Design里面的一些触发方法,如OnChange,OnSelect等等,当你触发时,该时间会自动传一些值给方法. 这是Select里面的onChange调用,在红框中,他会自动传 ...

  2. 如何把已有的本地git仓库,推送到远程新的仓库(github private)并进行远程开发;

    最近因为疫情,在家干活,连接不上之前的gitlab 服务器:所以不得把现有的代码迁移到github 的私有仓库来进行开发:下面简要记录迁移的过程: 首先,确保你已经配置好本地访问远程私有仓库的所有权限 ...

  3. cjson库的移植和使用

    cjson 下载链接 https://github.com/DaveGamble/cJSON 下载完成将其中的cJson.c cJson.h复制到自己的项目中引用即可: 1.字符串转json格式 cJ ...

  4. RocketMQ幂等性问题

    什么是幂等性: 在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同. 当出现消费者对某条消息重复消费的情况时,重复消费的结果与消费一次的结果是相同的,并且多次消费并未对业务系 ...

  5. QingTing.Fm-WPF是调用蜻蜓FMAPI 查询API内容展示,进行播放

    QingTing.Fm 是调用蜻蜓FM   API 查询界面内容,进行在线播放. Release地址下载 环境 Visual Studio 2019,dotNet Framework 4.6.1 SD ...

  6. 洛谷P4525 【模板】自适应辛普森法1与2

    洛谷P4525 [模板]自适应辛普森法1 与P4526[模板]自适应辛普森法2 P4525洛谷传送门 P4525题目描述 计算积分 结果保留至小数点后6位. 数据保证计算过程中分母不为0且积分能够收敛 ...

  7. 一些实用的GitHub项目

    原文链接:http://www.louisvv.com/archives/2036.html 最近整理了一些在GitHub上比较热门的开源项目 关于GitHub,快速了解请戳这里 其中涵盖了:学习教程 ...

  8. phpcms搜索给分页代码添加参数方法

    在使用PHPCMS开发网站时遇到了一个搜索功能,需要在搜索结果分页链接上添加一些传递的参数,不然不能够正确翻页. 方法: 找到\phpcms\libs\functions\global.func.ph ...

  9. 神经网络反向传播算法&&卷积神经网络

    听一遍课程之后,我并不太明白这个算法的奇妙之处?? 为啥? 神经网络反向传播算法 神经网络的训练依靠反向传播算法,最开始输入层输入特征向量,网络层计算获得输出,输出层发现输出和正确的类号不一样,这时就 ...

  10. JavaDay10(上)

    Java learning_Day10(上) 本人学习视频用的是马士兵的,也在这里献上 <链接:https://pan.baidu.com/s/1qKNGJNh0GgvlJnitTJGqgA&g ...