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(); } }