Unity基础之C#核心篇笔记4:多态
多态
1.多态的概念
// 多态按字面的意思就是“多种状态”
// 让继承同一父类的子类们 在执行相同方法时有不同的表现(状态)
// 主要目的
// 同一父类的对象 执行相同行为(方法)有不同的表现
// 解决的问题
// 让同一个对象有唯一行为的特征
2.解决的问题
//让同一个对象有唯一行为的特征
class Father
{
public void SpeakName()
{
Console.WriteLine("Father的方法");
}
}
class Son:Father
{
public new void SpeakName()
{
Console.WriteLine("Son的方法");
}
}
3.多态的实现
//我们目前已经学过的多态
//编译时多态——函数重载,开始就写好的
//我们将学习的:
//运行时多态( vob、抽象函数、接口 )
//我们今天学习 vob
//v: virtual(虚函数)
//o: override(重写)
//b: base(父类)
class GameObject
{
public string name;
public GameObject(string name)
{
this.name = name;
}
//虚函数 可以被子类重写
public virtual void Atk()
{
Console.WriteLine("游戏对象进行攻击");
}
}
class Player:GameObject
{
public Player(string name):base(name)
{
}
//重写虚函数
public override void Atk()
{
//base的作用
//代表父类 可以通过base来保留父类的行为
base.Atk();
Console.WriteLine("玩家对象进行攻击");
}
}
class Monster:GameObject
{
public Monster(string name):base(name)
{
}
public override void Atk()
{
Console.WriteLine("怪物对象进行攻击");
}
}
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("多态vob");
#region 解决的问题
Father f = new Son();
f.SpeakName();
(f as Son).SpeakName();
#endregion
#region 多态的使用
GameObject p = new Player("唐老狮");
p.Atk();
(p as Player).Atk();
GameObject m = new Monster("小怪物");
m.Atk();
(m as Monster).Atk();
#endregion
}
}
4.总结
//多态:让同一类型的对象,执行相同行为时有不同的表现
//解决的问题: 让同一对象有唯一的行为特征
//vob:
// v:virtual 虚函数
// o:override 重写
// b:base 父类
// v和o一定是结合使用的 来实现多态
// b是否使用根据实际需求 保留父类行为
抽象类和抽象方法
1.抽象类
//概念
//被抽象关键字abstract修饰的类
//特点:
//1.不能被实例化的类
//2.可以包含抽象方法
//3.继承抽象类必须重写其抽象方法
abstract class Thing
{
//抽象类中 封装的所有知识点都可以在其中书写
public string name;
//可以在抽象类中写抽象函数
}
class Water:Thing
{
}
2.抽象函数
//又叫 纯虚方法
//用 abstract关键字修饰的方法
//特点:
//1.只能在抽象类中申明
//2.没有方法体
//3.不能是私有的
//4.继承后必须实现 用override重写
abstract class Fruits
{
public string name;
//抽象方法 是一定不能有函数体的
public abstract void Bad();
public virtual void Test()
{
//可以选择是否写逻辑
}
}
class Apple : Fruits
{
public override void Bad()
{
}
//虚方法是可以由我们子类选择性来实现的
//抽象方法必须要实现
}
class SuperApple:Apple
{
//虚方法和抽象方法 都可以被子类无限的 去重写
public override void Bad()
{
base.Bad();
}
public override void Test()
{
base.Test();
}
}
#endregion
class Program
{
static void Main(string[] args)
{
Console.WriteLine("抽象类和抽象方法");
//抽象不能被实例化
//Thing t = new Thing();
//但是 可以遵循里氏替换原则 用父类容器装子类
Thing t = new Water();
}
}
3.总结
//抽象类 被abstract修饰的类 不能被实例化 可以包含抽象方法
//抽象方法 没有方法体的纯虚方法 继承后必须去实现的方法
//注意:
//如何选择普通类还是抽象类
//不希望被实例化的对象,相对比较抽象的类可以使用抽象类
//父类中的行为不太需要被实现的,只希望子类去定义具体的规则的 可以选择 抽象类然后使用其中的抽象方法来定义规则
//作用:
//整体框架设计时 会使用
4.练习题
1.练习题1*
//写一个动物抽象类,写三个子类
//人叫,狗叫,猫叫
abstract class Animal
{
public abstract void Speak();
}
class Person : Animal
{
public override void Speak()
{
Console.WriteLine("你好");
}
}
class Dog:Animal
{
public override void Speak()
{
Console.WriteLine("汪汪");
}
}
class Cat:Animal
{
public override void Speak()
{
Console.WriteLine("喵喵");
}
}
2.练习题2*
//创建一个图形类,有求面积和周长两个方法
//创建矩形类,正方形类,圆形类继承图形类
//实例化矩形、正方形、圆形对象求面积和周长
abstract class Graph
{
public abstract float GetLength();
public abstract float GetArea();
}
class Rect : Graph
{
private float w;
private float h;
public Rect(int w, int h)
{
this.w = w;
this.h = h;
}
public override float GetLength()
{
return 2 * (w + h);
}
public override float GetArea()
{
return w * h;
}
}
class Square : Graph
{
private float l;
public Square(int l)
{
this.l = l;
}
public override float GetLength()
{
return 4 * l;
}
public override float GetArea()
{
return l * l;
}
}
class Circular : Graph
{
private float r;
public Circular(float r)
{
this.r = r;
}
public override float GetLength()
{
return 2 * 3.14f * r;
}
public override float GetArea()
{
return 3.14f * r * r;
}
}
接口
1.接口的概念
//接口是行为的抽象规范
//它也是一种自定义类型
//关键字 :interface
//接口申明的规范
//1.不包含成员变量
//2.只包含方法、属性、索引器、事件
//3.成员不能被实现
//4.成员可以不用写访问修饰符,不能是私有的
//5.接口不能继承类,但是可以继承另一个接口
//接口的使用规范
//1.类可以继承多个接口
//2.类继承接口后,必须实现接口中所有成员
//特点:
//1.它和类的申明类似
//2.接口是用来继承的
//3.接口不能被实例化,但是可以作为容器存储对象
2. 接口的申明
//接口关键字:interface
//语法:
// interface 接口名
// {
// }
//一句话记忆:接口是抽象行为的“基类”
//接口命名规范 帕斯卡前面加个I
interface IFly
{
void Fly();
string Name
{
get;
set;
}
int this[int index]
{
get;
set;
}
event Action doSomthing;
}
3.接口的使用
//接口用来继承
class Animal
{
}
//1.类可以继承1个类,n个接口
//2.继承了接口后 必须实现其中的内容 并且必须是public的
class Person : Animal, IFly
{
//3.实现的接口函数,可以加v再在子类重写
public virtual void Fly()
{
}
public string Name
{
get;
set;
}
public int this[int index]
{
get
{
return 0;
}
set
{
}
}
public event Action doSomthing;
}
4.接口可以继承接口
//接口继承接口时 不需要实现
//待类继承接口后 类自己去实现所有内容
interface IWalk
{
void Walk();
}
interface IMove : IFly, IWalk
{
}
class Test : IMove
{
public int this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public event Action doSomthing;
public void Fly()
{
throw new NotImplementedException();
}
public void Walk()
{
throw new NotImplementedException();
}
}
5.显示实现接口
//当一个类继承两个接口
//但是接口中存在着同名方法时
//注意:显示实现接口时 不能写访问修饰符
interface IAtk
{
void Atk();
}
interface ISuperAtk
{
void Atk();
}
class Player : IAtk, ISuperAtk
{
//显示实现接口 就是用 接口名.行为名 去实现
void IAtk.Atk()
{
}
void ISuperAtk.Atk()
{
}
public void Atk()
{
}
}
6.总结
继承类:是对象间的继承,包括特征行为等等
继承接口:是行为间的继承,继承接口的行为规范,按照规范去实现内容
由于接口也是遵循里氏替换原则,所以可以用接口容器装对象
那么就可以实现装载各种毫无关系,但是却有相同行为的对象
注意:
1.接口值包含 成员方法、属性、索引器、事件,并且都不实现,都没有访问修饰符
2.可以继承多个接口,但是只能继承一个类
3.接口可以继承接口,相当于在进行行为合并,待子类继承时再去实现具体的行为
4.接口可以被显示实现 主要用于实现不同接口中的同名函数的不同表现
5.实现的接口方法 可以加 virtual关键字 之后,让子类进行重写
7.练习题
1.练习题1
//人、汽车、房子都需要登记,人需要到派出所登记,汽车需要去车管所登记,房子需要去房管局登记
//使用接口实现登记方法
interface IRegister
{
void Register();
}
class Person:IRegister
{
public void Register()
{
Console.WriteLine("派出所登记");
}
}
class Car:IRegister
{
public void Register()
{
Console.WriteLine("车管所登记");
}
}
class Home:IRegister
{
public void Register()
{
Console.WriteLine("房管局登记");
}
}
2.练习题2
//麻雀、鸵鸟、企鹅、鹦鹉、直升机、天鹅
//直升机和部分鸟能飞
//鸵鸟和企鹅不能飞
//企鹅和天鹅能游泳
//除直升机,其它都能走
//请用面向对象相关知识实现
abstract class Bird
{
public abstract void Walk();
}
interface IFly
{
void Fly();
}
interface ISwimming
{
void Swimming();
}
class Sparrow : Bird, IFly
{
public void Fly()
{
}
public override void Walk()
{
}
}
class Ostrich:Bird
{
public override void Walk()
{
}
}
class Penguin : Bird,ISwimming
{
public void Swimming()
{
}
public override void Walk()
{
}
}
class Parrot : Bird,IFly
{
public void Fly()
{
}
public override void Walk()
{
}
}
class Swan : Bird,IFly,ISwimming
{
public void Fly()
{
}
public void Swimming()
{
}
public override void Walk()
{
}
}
class Helicopter : IFly
{
public void Fly()
{
}
}
3.练习题3
//多态来模拟移动硬盘、U盘、MP3查到电脑上读取数据
//移动硬盘与U盘都属于存储设备
//MP3属于播放设备
//但他们都能插在电脑上传输数据
//电脑提供了一个USB接口
//请实现电脑的传输数据的功能
interface IUSB
{
void ReadData();
}
class StorageDevice : IUSB
{
public string name;
public StorageDevice(string name)
{
this.name = name;
}
public void ReadData()
{
Console.WriteLine("{0}传输数据", name);
}
}
class MP3 : IUSB
{
public void ReadData()
{
Console.WriteLine("MP3传输数据");
}
}
class Computer
{
public IUSB usb1;
}
#endregion
class Program
{
static void Main(string[] args)
{
StorageDevice hd = new StorageDevice("移动硬盘");
StorageDevice ud = new StorageDevice("U盘");
MP3 mp3 = new MP3();
Computer c = new Computer();
c.usb1 = hd;
c.usb1.ReadData();
c.usb1 = ud;
c.usb1.ReadData();
c.usb1 = mp3;
c.usb1.ReadData();
}
}
密封方法
1.密封方法基本概念
用密封关键字sealed 修饰的重写函数
作用:让虚方法或者抽象方法之后不能再被重写
特点:和override一起出现
2.实例
abstract class Animal
{
public string name;
public abstract void Eat();
public virtual void Speak()
{
Console.WriteLine("叫");
}
}
class Person:Animal
{
public override void Eat()
{
}
public override void Speak()
{
}
}
class WhitePerson:Person
{
public sealed override void Eat()
{
base.Eat();
}
public sealed override void Speak()
{
base.Speak();
}
}
3.总结
密封方法 可以让虚方法和抽象方法不能再被子类重写
特点:一定是和override一起出现