学习Unity: 理解C#多态

多态的概念:多态的实现是建立在继承的基础上实现的,当父类引用指向子类对象时,同一操作,可以产生不同的行为

一.关键字解释,虚方法,抽象方法,重写,重载,覆盖,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();
    }
}

输出

 

可以看出以上三种方法输出都是一样的,大家根据自己的需求可以选择较优的方式实现~

好了,文章到此就结束了,本文有什么错误的观点或者用法,希望各位看官能够及时提出,希望在自己积累知识的同时,能帮助到大家~

 

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值