多态的概念:多态的实现是建立在继承的基础上实现的,当父类引用指向子类对象时,同一操作,可以产生不同的行为
一.关键字解释,虚方法,抽象方法,重写,重载,覆盖,base,this
1.虚方法(virtual):当一个方法(属性)使用关键字virtual修饰的时候,这个时候就说明此方法(属性)为虚方法(属性),子类可以重写此方法(属性),从而实现多态,虚方法是可以定义方法体的,可就是说这个函数是有作用的,可以实现具体功能的
public virtual void DoSomething()
{
Debug.Log("写作业");
}
2.抽象方法(abstract):首先关键字abstract可以修饰类,函数,属性,当类中的属性或者函数使用abstract修饰的时候,则该类必须为abstract修饰的抽象类抽象类是不能被实例化的,只能用来被继承,所以不能使用关键字sealed(密封类)来修饰,当一个函数(属性)被abstract修饰后,那么这个函数(属性)就是抽象函数(属性),那么继承此抽象类的子类必须重写此方法,从而实现多态,抽象函数(属性)是不能有函数体的
public abstract class Stud
{
public abstract string Name { get; set; }
public abstract void DoSomething();
}
3.重写(override)是在子类中重写父类中使用virtual或者abstract修饰的方法(属性)。用于扩展或修改继承的方法(属性)实现。提供从基类继承的成员的新实现,从而实现多态
public abstract class Person
{
public abstract void DoSomething();
}
public class Stud : Person
{
public override void DoSomething()
{
Debug.Log("实现");
}
}
4.重载(overload):当然overload并不是重载的关键字,重载并没有关键字,重载与重写一字之差,但是两者一点关系都木有~重载就是一个类中有N个重名函数,但是他们的参数类型或者个数不相同,当然顺序不相同也是可以的,调用的时候,会自动根据你填写的参数类型,个数来调用匹配的重载(注意:和返回值木有任何关系)
public class OverLoad
{
public void Test(int a) { }
public void Test(string a) { }
public void Test(string a, int b) { }
public void Test(int b, string a) { }
}
覆盖(new):说简单点来说当子类拥有了和父类重名的函数时,又没有使用override重写,这个时候就会出现问题,隐藏了父类某某某方法,建议使用new关键字,这个时候当你使用了new关键字了之后,这两个同名函数就一点关系都没有了,相当于同名的两个不同的函数
public class Test : MonoBehaviour
{
private void Start()
{
Stud stud = new Stud();
stud.Test();
//输出Stud
Person person1 = new Person();
person1.Test();
//输出Person
Person person2 = new Stud();
person2.Test();
//输出Person
}
}
public class Person
{
public void Test() { Debug.Log("Person"); }
}
public class Stud : Person
{
public new void Test() { Debug.Log("Stud"); }
}
base:指的是该子类继承的父类
this:自己类本身
二.多态的实现方式
1.利用关键字virtual与override实现多态
// 父类
public class Person
{
//名字
public string m_name;
//年龄
public int m_age;
//昵称
public string m_nickname;
public Person(string name, int age, string nickname)
{
m_name = name;
m_age = age;
m_nickname = nickname;
}
//用virtual修饰属性,已达到子类可以重写属性目的
public virtual string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
//虚方法用于子类重写以达到实现多态的目的
public virtual void Work()
{
Debug.Log("人们正在努力工作");
}
}
//子类
public class Student : Person
{
//继承父类构造
public Student(string name, int age, string nickname) : base(name, age, nickname) { }
//学生因为比较可爱,所以名字应该是他的昵称,所以我们应该重写Name属性
public override string Name
{
get
{
return m_nickname;
}
set
{
m_nickname = value;
}
}
//学生每天的作业可能就是学习了
public override void Work()
{
Debug.Log(Name + "正在学习知识");
}
}
//子类
public class Teacher : Person
{
//继承父类构造
public Teacher(string name, int age, string nickname) : base(name, age, nickname) { }
//老师比较严肃,工作的时候就不能就昵称了,因为virtual是可以有实现的,父类的实现刚好是显示m_name所以这里可以不用再重写了
public override void Work()
{
Debug.Log(Name + "正在备课");
}
}
实现多态
public class VirtualOverride : MonoBehaviour
{
void Start()
{
//父类引用指向子类对象
Person stud = new Student("王晓明同学", 10, "明明");
Person teacher = new Teacher("李铁柱老师", 30, "老李");
//调用一个函数,会产生不同的实现(同一操作,可以产生不同的行为)
LookWorkState(stud);
LookWorkState(teacher);
}
//查看Person的工作状态
private void LookWorkState(Person person)
{
person.Work();
}
}
输出
2.利用关键字abstract与override实现多态
// 父类
public abstract class Person
{
//名字
public string m_name;
//年龄
public int m_age;
//昵称
public string m_nickname;
public Person(string name, int age, string nickname)
{
m_name = name;
m_age = age;
m_nickname = nickname;
}
//用abstract修饰属性,已达到子类可以重写属性目的,这里是不能添加方法体实现的
public abstract string Name { get; set; }
//abstract用于子类重写以达到实现多态的目的,这里也是不能添加实现的
public abstract void Work();
}
//子类
public class Student : Person
{
//继承父类构造
public Student(string name, int age, string nickname) : base(name, age, nickname) { }
//学生因为比较可爱,所以名字应该是他的昵称
public override string Name
{
get
{
return m_nickname;
}
set
{
m_nickname = value;
}
}
//学生每天的作业可能就是学习了
public override void Work()
{
Debug.Log(Name + "正在学习知识");
}
}
//子类
public class Teacher : Person
{
//继承父类构造
public Teacher(string name, int age, string nickname) : base(name, age, nickname) { }
//老师比较严肃,工作的时候就不能就昵称了,因为父类是抽象类,所以子类要全部实现父类中的抽象属性与方法
public override string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public override void Work()
{
Debug.Log(Name + "正在备课");
}
}
这里的实现代码与输出都和使用关键字virtual与overload的是一样的
3.利用接口实现多态
//接口
interface IPerson
{
string Name { get; set; }
void Work();
}
public class Student : IPerson
{
//名字
public string m_name;
//年龄
public int m_age;
//昵称
public string m_nickname;
//构造函数
public Student(string name, int age, string nickname)
{
m_name = name;
m_age = age;
m_nickname = nickname;
}
//实现接口,学生可爱,所以大家都用昵称称呼他
public string Name
{
get
{
return m_nickname;
}
set
{
m_nickname = value;
}
}
public void Work()
{
Debug.Log(Name + "正在学习知识");
}
}
public class Teacher : IPerson
{
//名字
public string m_name;
//年龄
public int m_age;
//昵称
public string m_nickname;
//构造函数
public Teacher(string name, int age, string nickname)
{
m_name = name;
m_age = age;
m_nickname = nickname;
}
//实现接口,老师比较严肃,工作的时候就不能就昵称了
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public void Work()
{
Debug.Log(Name + "正在备课");
}
}
当然接口实现多态也可以新建父类,让父类实现接口,并对接口的Name与Work,使用关键字virtual或者abstract修饰,然后子类进行重写的,具体要看大家怎么使用了
//接口
interface IPerson
{
string Name { get; set; }
void Work();
}
//父类
public class Person : IPerson
{
//名字
public string m_name;
//年龄
public int m_age;
//昵称
public string m_nickname;
//构造函数
public Person(string name, int age, string nickname)
{
m_name = name;
m_age = age;
m_nickname = nickname;
}
public virtual string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public virtual void Work()
{
Debug.Log(Name + "正在备课");
}
}
//子类
public class Student : Person
{
//继承父类构造函数
public Student(string name, int age, string nickname) : base(name, age, nickname) { }
//实现接口,学生可爱,所以大家都用昵称称呼他
public override string Name
{
get
{
return m_nickname;
}
set
{
m_nickname = value;
}
}
public override void Work()
{
Debug.Log(Name + "正在学习知识");
}
}
//子类
public class Teacher : Person
{
//继承父类构造函数
public Teacher(string name, int age, string nickname) : base(name, age, nickname) { }
//实现接口,老师比较严肃,工作的时候就不能就昵称了
public override string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
public override void Work()
{
Debug.Log(Name + "正在备课");
}
}
实现多态
public class Interface : MonoBehaviour
{
void Start()
{
//父类引用指向子类对象
IPerson stud = new Student("王晓明同学", 10, "明明");
IPerson teacher = new Teacher("李铁柱老师", 30, "老李");
//调用一个函数,会产生不同的实现(同一操作,可以产生不同的行为)
LookWorkState(stud);
LookWorkState(teacher);
}
//查看Person的工作状态
private void LookWorkState(IPerson person)
{
person.Work();
}
}
输出
可以看出以上三种方法输出都是一样的,大家根据自己的需求可以选择较优的方式实现~
好了,文章到此就结束了,本文有什么错误的观点或者用法,希望各位看官能够及时提出,希望在自己积累知识的同时,能帮助到大家~