多态vob 多态的概念 说人话就是“多种状态”
让继承同一父类的子类们,在执行相同方法是有不同的表现(状态)
主要目的 同一父类的对象执行相同的方法,会有不同的表现。因此这样可以让同一的对象有唯一行为的特征
解决的问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using System;namespace vob { class Father { public void SpeakName () { Console.WriteLine("Father的方法" ); } } class Son :Father { public new void SpeakName () { Console.WriteLine("Son的方法" ); } } class Program { static void Main (string [] args ) { Console.WriteLine("" ); Father f = new Son(); f.SpeakName(); (f as Son).SpeakName(); } } }
多态的实现 看到这里的小伙伴可能好奇,vob是什么意思呢?vob是三个名词的缩写即
v(virtual)—-虚函数
o(override)—-重写
b(base)—-父类
这三个是方便记忆而编写的,并不是官方术语
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 using System;namespace vob { class GameObject { public string name; public GameObject (string name ) { this .name = name; } public virtual void Atk () { Console.WriteLine("游戏对象进行攻击" ); } } class Player :GameObject { public Player (string name ):base (name ) { } public override void Atk () { base .Atk(); Console.WriteLine("玩家的攻击" ); } } class Monster : GameObject { public Monster (string name ) : base (name ) { } public override void Atk () { Console.WriteLine("怪物的攻击" ); } } class Program { static void Main (string [] args ) { GameObject p = new Player("铅笔沫" ); p.Atk(); (p as Player).Atk(); GameObject m = new Monster("怪物" ); m.Atk(); (m as Monster).Atk(); } } }
练习题 Q1:
真的鸭子嘎嘎叫,木头鸭子吱吱叫,橡皮鸭子唧唧叫
Q2:
所有员工9点打卡,但是经理十一点,程序员不打卡
Q3:
创建一个图形类,有求面积和周长两个方法,创建矩形类,正方形类,圆形类,继承图形类,实例化矩形、正方形、圆形对象求面积和周长
A1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 using System;namespace homework { class Duck { public virtual void Speak () { Console.WriteLine("真的鸭子嘎嘎叫" ); } } class Wood : Duck { public override void Speak () { Console.WriteLine("木头鸭子吱吱叫" ); } } class Rubber : Duck { public override void Speak () { Console.WriteLine("橡胶鸭子唧唧叫" ); } } class Program { public static void Main (string [] args ) { Duck d = new Duck(); d.Speak(); Duck d2 = new Wood(); d2.Speak(); Duck d3 = new Rubber(); d3.Speak(); } } }
A2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 using System;namespace homework { class Staff { public virtual void PunchTheClock () { Console.WriteLine("9点打卡" ); } } class Manager : Staff { public override void PunchTheClock () { Console.WriteLine("11点打卡" ); } } class Programmer : Staff { public override void PunchTheClock () { Console.WriteLine("老子不打卡" ); } } class Program { public static void Main (string [] args ) { Staff staff = new Staff(); staff.PunchTheClock(); Manager manager = new Manager(); manager.PunchTheClock(); Programmer programmer = new Programmer(); programmer.PunchTheClock(); } } }
A3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 using System;namespace homework { class Graph { public virtual float GetLength () { return 0 ; } public virtual float GetArea () { return 0 ; } } class Rect :Graph { private float w; private float h; public Rect (float w, float h ) { this .w = w; this .h = h; } public override float GetLength () { return 2 *(w+h); } public override float GetArea () { return w * h; } } class Square :Graph { private float l; public Square (float l ) { this .l = l; } public override float GetLength () { return 4 *l; } public override float GetArea () { return l*l; } } class Circular :Graph { private float r; public Circular (float r ) { this .r = r; } public override float GetLength () { return 2 *3.14f *r; } public override float GetArea () { return 3.14f *r*r; } } class Program { public static void Main (string [] args ) { Rect rect = new Rect(2 ,3 ); Console.WriteLine(rect.GetLength()); Console.WriteLine(rect.GetArea()); Square square = new Spuare(3 ); Console.WriteLine(square.GetLength()); Console.WriteLine(square.GetArea()); Circular circular = new Circular(3 ); Console.WriteLine(circular.GetLength()); Console.WriteLine(circular.GetArea()); } } }
抽象类和抽象方法 抽象类 基本概念 就是被抽象关键字abstract修饰的类
特点
不能被实例化的类
可以包含抽象方法
继承抽象类必须重写其抽象方法
抽象类的子类可以通过里氏替换原则,进行实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using System;namespace homework { abstract class Thing { public string name; } class Water : Thing { } class Program { public static void Main (string [] args ) { Thing w = new Water(); } } }
抽象函数 基本概念
抽象函数,又称纯虚方法,用abstract关键字修饰的方法
特点
只能在抽象类中申明
没有函数(方法)体,只能定义(看不懂的话直接看下方代码)
不能是私有的
继承后必须使用override
重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using System; namespace homework { abstract class Fruits { public string name; public abstract void Bad () ; public virtual void Test () { } } class Apple :Fruits { public override void Bad () { } public override void Test () { } } class Banana :Fruits { public override void Bad () { } public override void Test () { } } class Program { public static void Main (string [] args ) { } } }
看到这里的小伙伴,可能会想,这两个给东西有什么用呢?
是这样的,当我们不希望被实例化的对象,相对比较抽象的类 可以使用抽象类例如(人 事物 水果 …),以及当父类中的行为,不太需要被是实现 ,只希望子类去定义具体规则的,可以选择使用抽象类,然后使用其中的方法来定义规则。
具体一点 当时设计整体框架时,就是它们大显身手的时候
练习题 Q1 写一个动物抽象类,写三个子类,分别为(人叫,狗叫,猫叫)
Q2 创建一个图形类,有求面积和周长两个方法,创建矩形类、正方形类、圆形类,继承图形类,实例化矩形、正方形、圆形对象求面积和周长
A1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using System;namespace homework { abstract class Animals { public abstract void Talk () ; } class Person :Animals { public override void Talk () { Console.WriteLine("人在叫" ); } } class Cats : Animals { public override void Talk () { Console.WriteLine("猫在叫" ); } } class Dogs : Animals { public override void Talk () { Console.WriteLine("狗在叫" ); } } class Program { public static void Main (string [] args ) { Animals p = new Person(); p.Talk(); Animals d = new Dogs(); d.Talk(); Animals c = new Cats(); c.Talk(); } } }
A2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 using System;namespace homework { abstract class Graph { public abstract float GetLength () ; public abstract float GetArea () ; } class Rect : Graph { private float w; private float h; public Rect (float w, float h ) { this .w = w; this .h = h; } public override float GetLength () { return 2 * (w + h); } public override float GetArea () { return w * h; } } class Square : Graph { private float l; public Square (float l ) { this .l = l; } public override float GetLength () { return 4 * l; } public override float GetArea () { return l * l; } } class Circular : Graph { private float r; public Circular (float r ) { this .r = r; } public override float GetLength () { return 2 * 3.14f * r; } public override float GetArea () { return 3.14f * r * r; } } class Program { public static void Main (string [] args ) { Graph rect = new Rect(2 , 3 ); Console.WriteLine(rect.GetLength()); Console.WriteLine(rect.GetArea()); Graph square = new Square(3 ); Console.WriteLine(square.GetLength()); Console.WriteLine(square.GetArea()); Graph circular = new Circular(3 ); Console.WriteLine(circular.GetLength()); Console.WriteLine(circular.GetArea()); } } }
接口 你可以把接口理解为是一种DLC,在原有的抽象类的基础上,增加一些特定的行为。例如,人与鸟,都属于动物,但是人不会飞,因此飞这个行为们就不适合写在动物恶的这个抽象类当中,所以可以通过接口,来给鸟类,来添加一种拓展的行为方式。并且这么写的好处还有,飞机类也可以使用飞的行为方式。因为接口可以被任何一个类继承。
基本概念 接口是行为的抽象规范,它也是一种自定义类型,关键字:interface
接口申明的规范
不 包含成员变量
只 包含方法、属性、索引器、事件
成员不能 被实现
成员可以不用写访问修饰符号(默认public ),但不能是私有 的
接口不能继承类,但是可以继承另一个接口
接口的使用规范
类可以继承多个接口
类继承接口后,必须实现接口中所有成员
特点
和类的申明类似
接口时用来继承的
接口不能被实例化,但是可以作为容器的存储对象(遵循里氏替换原则)
1 2 3 4 5 6 7 class Program { static void Main (string [] args ) { xxx f = new xxx(); } }
申明方法 基本语法
帮助记忆:接口时抽象行为的“基类”
命名规范:帕斯卡命名前加I
!!!!!!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using System;namespace homework { interface IFly { void Fly () ; string Name { get ; set ; } int this [int index] { get ; set ; } event Action dosomthing; } class Program { public static void Main (string [] args ) { } } }
使用方法 接口可以用来继承
1.一个类可以继承n个接口 1 2 3 4 class Person ,xxx ,xxxx { }
2.继承了接口后就必须实现其中的内容,并且必须是public的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Animal { } class Person :Animal ,IFly { public void Fly () { } public string Name { get ; set ; } public int this [int index] { get { return 0 ; } set { } } public event Action dosomthing; }
3.实现的接口函数可以加v(virtual)
再向子类中重写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Person :Animal ,IFly { public virtual void Fly () { } public string Name { get ; set ; } public int this [int index] { get { return 0 ; } set { } } public event Action dosomthing; }
4.接口也遵循里氏替换原则 1 2 3 4 5 6 7 class Program { static void Main (string [] args ) { IFly f = new Person(); } }
继承方式 接口是可以继承接口的
并且当接口继承接口时,不需要实现 ,而是通过后续 的类继承时,再去实现所有接口的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 using System;namespace homework { interface IFly { void Fly () ; string Name { get ; set ; } int this [int index] { get ; set ; } event Action dosomthing; } interface IWalk { void Walk () ; } interface IMove :IFly ,IWalk { void Move () ; } class Tset : IMove { public int this [int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public string Name { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public event Action dosomthing; public void Fly () { throw new NotImplementedException(); } public void Move () { throw new NotImplementedException(); } public void Walk () { throw new NotImplementedException(); } } class Program { public static void Main (string [] args ) { IMove im = new Tset(); IFly ifly = new Tset(); IWalk iw = new Tset(); } } }
有的小伙伴可能会疑问throw new NotImplementedException()
是什么意思呢 ?这是VS中给类快速重构所有元素的一个方式,因为当一个子类的父类是抽象类,或者含有虚函数,抽象函数等,需要在类中重新书写的元素,再不定义之前,会进行报错。因此可以使用快速重构的方式,通过使用throw new NotImplementedException()
来进行占位,意思是提醒你在这个位置,你还没有进行重写。
显式实现接口 这是一个使用性并不是很强的东西,但面试的时候可能会需要。
当一个类继承两个接口时,接口中有同名重复的时候,所使用的一个方法。
值得注意的是:显示实现接口时,不能写访问修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 using System;namespace homework { interface IAtk { void Atk () ; } interface ISuperAtk { void Atk () ; } class Player : IAtk , ISuperAtk { void IAtk.Atk() { throw new NotImplementedException(); } void ISuperAtk.Atk() { throw new NotImplementedException(); } } class Program { public static void Main (string [] args ) { IAtk ia = new Player(); ia.Atk(); ISuperAtk isa = new Player(); isa.Atk(); Player p =new Player(); (p as IAtk).Atk(); (p as ISuperAtk).Atk(); } } }
练习题 Q1 人、汽车、房子都需要登记,人需要到派出所登记,汽车需要去车管所登记,房子需要去房管局登记 使用接口实现登记方法
Q2 麻雀、鸵鸟、企鹅、鹦鹉、直升机、天鹅。直升机和部分鸟能飞 鸵鸟和企鹅不能飞企鹅和天鹅能游泳 除直升机,其它都能走 请用面向对象相关知识实现
Q3 多态来模拟移动硬盘、U盘、MP3查到电脑上读取数据移动硬盘与U盘都属于存储设备 MP3属于播放设备 但他们都能插在电脑上传输数据电脑提供了一个USB接口 请实现电脑的传输数据的功能
A1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using System;using System.Diagnostics;namespace homework { interface IRegister { void Register () ; } class Person :IRegister { public void Register () { Console.WriteLine("在派出所登记" ); } } class Car :IRegister { public void Register () { Console.WriteLine("在车管所登记" ); } } class House :IRegister { public void Register () { Console.WriteLine("在房管局登记" ); } } class Program { public static void Main (string [] args ) { IRegister[] arr = new IRegister[] { new Person(), new Home(), new Car() }; for (int i = 0 ; i < arr.Length; i++) { arr[i].Register(); } } } }
A2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 using System;using System.Diagnostics;namespace homework { abstract class Bird { public abstract void Walk () ; } interface IFly { void Fly () ; } interface ISwimming { void Swimming () ; } class Sparrow : Bird , IFly { public void Fly () { } public override void Walk () { } } class Ostrich : Bird { public override void Walk () { } } class Penguin : Bird , ISwimming { public void Swimming () { } public override void Walk () { } } class Parrot : Bird , IFly { public void Fly () { } public override void Walk () { } } class Swan : Bird , IFly , ISwimming { public void Fly () { } public void Swimming () { } public override void Walk () { } } class Helicopter : IFly { public void Fly () { } } class Program { public static void Main (string [] args ) { } } }
A3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 using System;using System.Diagnostics;namespace homework { interface IUSB { void ReadData () ; } class StorageDevice : IUSB { public string name; public StorageDevice (string name ) { this .name = name; } public void ReadData () { Console.WriteLine("{0}正在传输数据" , name); } } class MP3 : IUSB { public void ReadData () { Console.WriteLine("MP3传输数据" ); } } class Computer { public IUSB usb1; } class Program { public static void Main (string [] args ) { StorageDevice hd = new StorageDevice("移动硬盘" ); StorageDevice ud = new StorageDevice("U盘" ); MP3 mp3 = new MP3(); Computer c = new Computer(); c.usb1 = hd; c.usb1.ReadData(); c.usb1 = ud; c.usb1.ReadData(); c.usb1 = mp3; c.usb1.ReadData(); } } }