C# 面向对象编程【多态详解】

C# 面向对象编程【多态详解】

1. 里氏转换

1)、子类可以赋值给父类
2)、如果父类中装的是子类对象,那么可以讲这个父类强转为子类对象

声明

public class Person
{
    
    
    public void PersonSayHello()
    {
    
    
        Console.WriteLine("我是父类");
    }
}
public class Student : Person
{
    
    
    public void StudentSayHello()
    {
    
    
        Console.WriteLine("我是学生");
    }
}

里氏转换例子

1)、父类可以装子类对象
//方式1
Person p = new Student();
//方式2
Student s = new Student();
Person p = s
2)、如果父类中装的是子类对象,那么可以讲这个父类强转为子类对象。
//a
Person pp = new Student();
if (pp is Student)
{
    
    
    Student ss = (Student)p;
    ss.StudentSayHello();
}
else
{
    
    
    Console.WriteLine("转换失败");
}
//b
Student t = pp as Student;
if (t != null)
{
    
    
    t.StudentSayHello();
}

is:因为如果转换失败会抛异常,所以用is来判断是否是Student类,或说是否是Student类型;

as: 如果不能转换,会返回null给 t

一个常见的例子

//栗子,Join()的第二个参数是object()类,但我们给的是string数组,即object的子类
//string str = string.Join("|",new string[] { "1", "2", "3", "4" });

2. 多态

概念:让一个对象能够表现出多种的状态(类型)

其实就是用父类装子类,精简代码,方便操作多个同父类的子类

实现多态的3种手段:1、虚方法 2、抽象类 3、接口

2.1 虚方法

步骤:
1、将父类的方法标记为虚方法 ,使用关键字 virtual,这个函数可以被子类重新写一个遍。

父类
public virtual void SayHello()
子类
public override void SayHello()
using System;

namespace _09多态
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Chinese cn1 = new Chinese("韩梅梅");
            Chinese cn2 = new Chinese("李雷");
            Japanese j1 = new Japanese("树下君");
            Japanese j2 = new Japanese("井边子");
            
            Person[] pers = {
    
     cn1, cn2, j1, j2, new English("格林"), new English("玛利亚") };

            for (int i = 0; i < pers.Length; i++)
            {
    
    
                // 会根据装的子类调用各自的SayHello()函数
                pers[i].SayHello();
            }
            Console.ReadKey();
        }
    }

    public class Person
    {
    
    
        private string _name;
        public string Name
        {
    
    
            get {
    
     return _name; }
            set {
    
     _name = value; }
        }

        public Person(string name)
        {
    
    
            this.Name = name;
        }
        public virtual void SayHello()
        {
    
    
            Console.WriteLine("我是人类");
        }

    }

    public class Chinese : Person
    {
    
    
        public Chinese(string name)
            : base(name)
        {
    
    

        }

        public override void SayHello()
        {
    
    
            Console.WriteLine("我是中国人,我叫{0}", this.Name);
        }
    }
    public class Japanese : Person
    {
    
    
        public Japanese(string name)
            : base(name)
        {
    
     }

        public override void SayHello()
        {
    
    
            Console.WriteLine("我是脚盆国人,我叫{0}", this.Name);
        }
    }
    public class English : Person
    {
    
    
        public English(string name)
            : base(name)
        {
    
     }

        public override void SayHello()
        {
    
    
            Console.WriteLine("我是英国人");
        }
    }

}

3.2 抽象类

当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法。

父类

// 要点1,声明要用 abstract 不能实例化
public abstract class Animal
{
    
    
    // 要点2 抽象方法,不能有方法体
    public abstract void Bark();
    // 要点3 抽象属性,get不能有方法体,而且不能要对应字段
    public abstract string Name
    {
    
    
        get;
        set;
    }
    //一般只有抽象成员,要不然写成虚方法更好
    // 可以有非抽象成员
    public virtual void T()
    {
    
    
        Console.WriteLine("动物有声明");
    }

    private int _age;//可以有非抽象字段
    public Animal()//空构造函数
    {
    
     

    }
}

子类


public class Cat : Animal
{
    
    
    //抽象类有的抽象成员都要实现
	//多态方法和虚方法一样
    public override void Bark()
    {
    
    
        Console.WriteLine("猫咪喵喵的叫");
    }	
    // 抽象属性实现,非抽象成员不用实现
    public override string Name
    {
    
    
        get
        {
    
    
            throw new NotImplementedException();
        }
        set
        {
    
    
            throw new NotImplementedException();
        }
    }
}

使用

Animal a = new Cat();//new Dog();
//Animal a = new Animal()这个是错误的,抽象类不能有实例
a.Bark();

3.3 接口

//接口就是一个规范、能力。

例如大家写代码要和接口的成员名称一样。

可以继承多个接口类

//语法,名称多是能够干什么
[public] interface I..able
{
	成员;
}

接口类

public interface IFlyable
{
    
    
    //接口中的成员不允许添加访问修饰符 ,默认就是public
    void Fly();
    string Test();
    //不允许写具有方法体的函数
	// 不能有字段
    string Name
    {
    
    
        get;
        set;
    }

}

子类

// 可以同时继承类和接口,但类要写在前面
//一定要实现接口成员
public class Birt : IFlyable 
{
	//自动属性
    public string Name
    {
        get;
        set;
    }
	//这样就可以实现多态,
    public void Fly()
    {
		//throw new NotImplementedException();//如果不写方法体可以写这句,也可以为空
    }
}

//自动属性
public string Name
{
get;
set;
}
//相当于
private string _name
public string Name
{
get {return _name;};
set {_name = value;};
}

使用

Birt b = new Birt();
b.Name = "dhf";

接口特点

接口可以继承接口

显式实现接口,显示实现接口就是为了解决方法的重名问题

namespace _14_显示实现接口
{
     
     
   class Program
   {
     
     
       static void Main(string[] args)
       {
     
     
           //显示实现接口就是为了解决方法的重名问题
           IFlyable fly = new Bird();
           fly.Fly();
           Bird bird = new Bird();
           bird.Fly();

           Console.ReadKey();
       }
   }
   public class Bird : IFlyable
   {
     
     
       public void Fly()
       {
     
     
           Console.WriteLine("鸟飞会");
       }
       /// <summary>
       /// 显示实现接口,不能使用public修饰
       /// </summary>
        void IFlyable.Fly()
       {
     
     
           Console.WriteLine("我是接口的飞");
       }

   }

   public interface IFlyable
   {
     
     
       void Fly();
   }
}

猜你喜欢

转载自blog.csdn.net/qq_38463737/article/details/113617869