多态
- 概念:让一个对象能够表现出多种的状态(类型),最大效益的取消差异性,增强可扩展性
-
多态的效果:让下面那行代码可以实现上面那坨代码的效果
父类Person类,有Chinese,Japanese,Korea,American四个子类 - 实现多态的三种手段:1、虚方法 2、抽象类 3、接口
虚方法
步骤:
1.将父类的方法标记为虚方法,使用关键字virtual;虚方法的效果是这个函数可以被子类重写一遍
将父类的方法标记为虚方法,使用关键字virtual
2.将子类的方法使用关键字override标记;(如果不实现多态,不加override也不会报错。不加override的时候实现的还是原来的Person类的SayHello方法)
子类方法加个override
原理:调用的还是父类Person类的SayHello方法,只是这个方法在子类Chinese,Japanese,Korea,American里面被重写了。具体调用哪个子类取决于pers[i]里面装的是哪个子类对象。
取决于pers[i]里面装的是哪个子类对象
class Program
{
static void Main(string[] args)
{
Person[] p = new Person[3];
p[0] = new Person();
p[1] = new Chinese();
p[2] = new Japanese();
foreach (var item in p)
{
item.sayHello();
}
}
public class Person
{
public virtual void sayHello()
{
Console.WriteLine("father class: Person");
}
}
public class Chinese:Person
{
public override void sayHello()
{
Console.WriteLine("Son class:Person");//子类重写显示子类的方法
}
}
public class Japanese : Person
{
//子类不重写显示父类的方法
}
}
上述代码运行效果
注意:
父类是最广泛的本质的类,如(经理,员工,程序员)选择员工作为父类,因为经理和程序员也是员工。
例题一 给出了父类(员工 )
namespace 多态实现之虚方法
{
class Program
{
static void Main(string[] args)
{
//经理十一点打卡,员工九点打卡,程序员不打卡
Manager ma = new Manager();
Employee em = new Employee();
Dev dev = new Dev();
Employee[] emp = {ma , em, dev};
for (int i = 0; i < emp.Length; i++)
{
emp[i].Daka();
}
Console.ReadKey();
}
}
public class Manager : Employee
{
public override void Daka()
{
Console.WriteLine("经理十一点打卡");
}
}
public class Employee
{
public virtual void Daka()
{
Console.WriteLine("员工九点打卡");
}
}
public class Dev :Employee
{
public override void Daka()
{
Console.WriteLine("程序员不打卡");
}
}
}
抽象类
适用: 当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法(抽象方法没有方法体,就是{ })
注意:
-
抽象类和接口不允许创建对象,因此放cat()类型的对象 -
抽象成员必须被标记为abstract,并且不能有任何实现。
这个是抽象属性(get和set不算实现吗??)
错误原因:两个子类没有实现继承的抽象属性
-
抽象成员必须在抽象类中。
-
子类继承抽象类后,必须把父类中的所有抽象成员都重写。(除非子类也是一个抽象类,则可以不重写)
解决上图错误:把父类中的所有抽象成员都重写 -
抽象成员的访问修饰符不能是private。
-
在抽象类中可以包含实例成员,也可以包含虚方法。并且抽象类的实例成员可以不被子类实现。
-
抽象类是有构造函数的,虽然不能被实例化。
-
如果父类的抽象方法中有参数,那么,继承这个抽象父类的子类在重写父类的方法的时候必须传入对应的参数。
如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候,也必须要传入返回值。 -
如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义为一个普通类,用虚方法来实现。
如果父类中的方法没有默认的实现,父类也不需要被实例化,则可以将该类定义为抽象类。
签名就是返回值+参数
例题二 未给出父类
class Program
{
static void Main(string[] args)
{
//狗狗会叫 猫咪也会叫
Animal an = new Dog();
an.Bark();
}
public abstract class Animal
{
public abstract void Bark();
}
public class Dog: Animal
{
public override void Bark()
{
Console.WriteLine("汪汪汪");
}
}
public class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("miaomiaomiao");
}
}
}
例题三 抽象类练习
namespace 多态练习01
{
class Program
{
static void Main(string[] args)
{
Shape shape = new Circle(5); //new Rectangle(4,5);
Console.WriteLine("面积是{0},周长是{1}",shape.Area(),shape.Perimeter());
}
}
public abstract class Shape //父类
{
public abstract double Area();
public abstract double Perimeter();
}
public class Rectangle : Shape //子类
{
private double _length;
public double Length { get => _length; set => _length = value; }
private double _width;
public double Width { get => _width; set => _width = value; }
public Rectangle(double length,double width)
{
this.Length = length;
this.Width = width;
}
public override double Area()
{
return Length * Width;
}
public override double Perimeter()
{
return (Length + Width)*2;
}
}
public class Circle : Shape //子类
{
private double _radius;
public double Radius { get => _radius; set => _radius = value; }
public Circle(double r)
{
this.Radius = r;
}
public override double Area()
{
return Math.PI * Radius * Radius;
}
public override double Perimeter()
{
return Math.PI * 2 * Radius;
}
}
}
例题四 抽象类练习
这里注意:要用电脑进行读取,用此类调用别的类的方法
namespace 电脑读取硬盘磁盘U盘
{
class Program
{
static void Main(string[] args)
{
//用U盘实现将移动硬盘,MP3,U盘插到电脑上进行读的操作
MobileStorage ms = new UDisk();//Mp3();//MoblieDisk();
Computer cmp = new Computer();
cmp.cpuRead(ms);
cmp.cpuWrite(ms);
Console.ReadKey();
}
}
public abstract class MobileStorage //abstract关键字在class前面
{
public abstract void Read();
public abstract void Write();
}
public class MoblieDisk : MobileStorage
{
public override void Read()
{
Console.WriteLine("移动磁盘读");
}
public override void Write()
{
Console.WriteLine("移动磁盘写");
}
}
public class UDisk : MobileStorage
{
public override void Read()
{
Console.WriteLine("U盘读");
}
public override void Write()
{
Console.WriteLine("U盘写");
}
}
public class Mp3 : MobileStorage
{
public override void Read()
{
Console.WriteLine("Mp3读");
}
public override void Write()
{
Console.WriteLine("Mp3写");
}
public void playMusic()
{
Console.WriteLine("可以播放音乐");
}
}
public class Computer //亮点在这里!!要用电脑进行读取,用此类调用别的类的方法
{
public void cpuRead(MobileStorage ms)
{
ms.Read();
}
public void cpuWrite(MobileStorage ms)
{
ms.Write();
}
}
}
加上位置1,位置2就不用写入参数了
相应的主函数改成这样,这样封装的更极致
复习
List<>相比于ArrayList的优点:不用拆装箱(ArrayList是Object类型)
Dictionary<TKey,TValue>对于HashTable优点同上
网友评论