1.继承的特点:
继承顺序的不可逆性:继承是从上往下依此继承,而不能逆序进行。
继承的延续性:在继承顺序中,下一级具备上一级的属性和特征。
2.继承的好处:
代码复用,避免重复。
一处更新,处处更新。
3.继承的步骤和使用要点:
抽取公共部分,放到一个特定的类中(父类)。
其他类(子类)只需要继承父类,即可拥有父类特征(属性和方法)。
根据子类的需要添加属于自己的特征和方法。
4.继承的实现(和接口的实现形式类似)
在子类后面使用冒号“:”继承父类,如 class Dog : Animal
5.概念解释
子类继承父类,父类派生子类。
子类又叫派生类,父类又叫基类(超类)。
子类继承父类成员,也可以有自己独立的成员。
6.继承的条件
继承需要符合的关系:is-a 的关系 Cat is an Animal。
7.继承中的构造函数
this:可以使用this关键字访问父类成员(在构造函数中)。
base:调用父类的构造函数、调用父类的属性和方法。
1 public Dog(string name,string color,string kind,string favorite):base(name,color,kind) 2 { 3 this.Favorite=favorite; 4 }
1 class Animal 2 { 3 //父类构造函数 4 public Animal() { } 5 public Animal(string name, string color, string kind) 6 { 7 this.Color = color; 8 this.Name = name; 9 this.Kind = kind; 10 } 11 12 public string Name { get; set; }//名字 13 public string Color { get; set; }//颜色 14 public string Kind { get; set; }//种类 15 public string Favorite { get; set; }//喜好 16 } 17 18 class Dog : Animal 19 { 20 public Dog(string name, string color, string kind, string favorite) 21 : base(name, color, kind) 22 { 23 this.Favorite = favorite; 24 } 25 }
8.protected关键字
protected访问修饰符允许子类访问,而不允许其他非子类访问。
修饰符 | 类内部 | 子类 | 其他类 |
public | 可以 | 可以 | 可以 |
private | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 不可以 |
9子类调用父类构造函数总结
隐式调用:如果其他子类的构造函数没有使用base指明调用父类哪个构造函数时,子类会默认调用父类的无参构造函数:base()。这时父类要提供无参的构造函数。
显式调用:如果父类没有无参的构造函数,子类构造函数必须指明调用父类哪个构造函数。
10.继承的特性
继承的传递性:传递机制 A——>B B——>C C具有A的特性
继承的单根性:一个类只能有一个父类
例如机器视觉技术与软件学科又属于光学学科,能否同时继承两种人? 答案:不能
11.抽象类和抽象方法 abstract override
抽象方法就是在父类中未实现的方法,在子类中必须实现父类中的所有的抽象方法。
一个抽象类内可以没有抽象方法。
一个抽象方法所在的类必须是抽象类。
1 abstract class Animal 2 { 3 public string Name {get;set;} 4 public Animal(){} 5 //用abstract修饰抽象方法 6 public abstract void Have(); 7 } 8 9 class Dog:Animal 10 { 11 //用override重写父类未实现的方法 12 public override void Have() 13 { 14 Console.WriteLine("狗吃骨头"); 15 } 16 } 17 18 class Cat:Anima 19 { 20 public override void Have() 21 { 22 Console.WriteLine("猫吃鱼"); 23 } 24 }
1 abstract class Animal 2 { 3 public string Name { get; set; }//名字 4 public string Color { get; set; }//颜色 5 public string Kind { get; set; }//种类 6 public string Favorite { get; set; }//喜好 7 //父类构造函数 8 public Animal() { } 9 public Animal(string name, string color, string kind) 10 { 11 this.Color = color; 12 this.Name = name; 13 this.Kind = kind; 14 } 15 //抽象方法 16 public abstract void Have(); 17 } 18 19 class Dog : Animal 20 { 21 public Dog(string name, string color, string kind, string favorite) 22 : base(name, color, kind) 23 { 24 this.Favorite = favorite; 25 } 26 public override void Have() 27 { 28 Console.WriteLine("我们要吃香喷喷的排骨啦!"); 29 } 30 } 31 32 class Cat : Animal 33 { 34 public Cat(string name, string color, string kind, string favorite) 35 : base(name, color, kind) 36 { 37 this.Favorite = favorite; 38 } 39 public override void Have() 40 { 41 Console.WriteLine("我们要吃香喷喷的烤鱼啦!"); 42 } 43 } 44 45 static void Main(string[] args) 46 { 47 //创建一只狗和一只猫 48 Cat objCat = new Cat("球球儿", "黄色", "小花猫", "小鱼"); 49 Dog objDog = new Dog("棒棒", "黑色", "小黑狗", "排骨"); 50 //将子类对象添加的父类集合 51 List<Animal> list = new List<Animal>(); 52 list.Add(objCat); 53 list.Add(objDog); 54 //取出子类对象 55 foreach (Animal obj in list) 56 { 57 obj.Have();//***********这就是多态*********** 58 } 59 Console.ReadLine(); 60 }
12.抽象类的概念与使用要点
12.1使用关键字abstract修饰的类,称为抽象类
12.2抽象类只是用来列举一个类所具有的行为,不能单独通过创建对象来使用,也就是说抽样类不能被new
12.3抽象类中可以有抽象方法,也可以没有任何抽象方法
12.4抽象类不能是静态的(static)或密封的(sealed),密封类不能被继承
13.抽象方法的概念与使用要点
13.1在抽象类中使用abstract修饰的方法,称为抽象方法
13.2抽象方法必须在抽象类中定义,不能在普通类中使用
13.3抽象方法只是一个方法的声明,不能有任何方法体
13.4抽象方法仅仅是表示一个应该具有的行为,具体实现由其子类实现
13.5抽象方法在子类中被实现(重写)必须使用关键字override
13.6子类必须重写父类的所有抽象方法,除非子类本身也是抽象类
14.多态
概念:不同对象,接受相同信息,产生不同行为,称为多态。
多态是由“聪明的”虚拟机自行决定的。
例如:子类重写了父类的抽象方法,父类集合中的对象直接调用抽象方法,实现子类中重写的抽象方法,可以称之为多态。
15.使用继承实现多态
15.1父类中必须有抽象方法或虚方法
15.2子类必须覆写(override)父类中的抽象方法或虚方法
15.3子类对象必须转换成父类类型去使用
多态的应用大大提高了程序的可扩展性
1 abstract class Animal 2 { 3 public string Name { get; set; }//名字 4 public string Color { get; set; }//颜色 5 public string Kind { get; set; }//种类 6 public string Favorite { get; set; }//喜好 7 //父类构造函数 8 public Animal() { } 9 public Animal(string name, string color, string kind) 10 { 11 this.Color = color; 12 this.Name = name; 13 this.Kind = kind; 14 } 15 //抽象方法 16 public abstract void Have(); 17 } 18 19 class Dog : Animal 20 { 21 public Dog(string name, string color, string kind, string favorite) 22 : base(name, color, kind) 23 { 24 this.Favorite = favorite; 25 } 26 //吃饭 27 public override void Have() 28 { 29 Console.WriteLine("我们要吃香喷喷的排骨啦!"); 30 } 31 } 32 33 class Cat : Animal 34 { 35 public Cat(string name, string color, string kind, string favorite) 36 : base(name, color, kind) 37 { 38 this.Favorite = favorite; 39 } 40 //吃饭 41 public override void Have() 42 { 43 Console.WriteLine("我们要吃香喷喷的烤鱼啦!"); 44 } 45 } 46 47 static void Main(string[] args) 48 { 49 //创建一只狗和一只猫 50 Cat objCat = new Cat("球球儿", "白色", "小花猫", "小鱼"); 51 Dog objDog = new Dog("棒棒", "黑色", "小黑狗", "排骨"); 52 //调用方法,传递子类对象 53 Test(objCat); 54 Test(objDog); 55 Console.ReadLine(); 56 }
16.里氏替换原则
16.1子类的对象能够替换父类
16.2父类对象不能够替换子类
16.3父类的方法都要在子类中实现或重写
解释:父类的范围广,父类包含子类,狗类属于动物类,但动物类不能仅属于狗类
17.is和as操作符
is操作符检查是否与指定类型兼容。如果转换失败程序中断
1 foreach (Animal obj in list) 2 { 3 if(obj is Cat) 4 Console.WriteLine("我是只猫"); 5 else if (obj is Dog) 6 Console.WriteLine("我是条狗"); 7 }
as操作符用于在兼容的引用类型之间执行转换,转换失败返回null
Cat cat = obj as Cat;
18.引入虚方法(虚方法和抽象方法的区别)
18.1抽象方法的特点:抽象方法仅仅是声明,没有任何实现内容;抽象方法一般必须在子类中被重写以后才有使用价值。
18.2如果父类中提供一个方法,要求由自己的方法体,子类根据自己的需要再决定是否需要重写此方法,该如何实现?————>>>>>>虚方法! 原来的abstract换成virtual。
18.3如果子类重写了虚方法,调用的就是子类的;如果子类未重写虚方法,调用的就是父类的。
1 //注意有虚方法的父类并不要添加abstract关键字 2 class Animal 3 { 4 public string Name { get; set; }//名字 5 public string Color { get; set; }//颜色 6 public string Kind { get; set; }//种类 7 public string Favorite { get; set; }//喜好 8 public Animal() { } 9 public Animal(string name, string color, string kind) 10 { 11 this.Color = color; 12 this.Name = name; 13 this.Kind = kind; 14 } 15 //虚方法 16 public virtual void Have() 17 { 18 Console.WriteLine("我们要吃饭啦!"); 19 } 20 } 21 22 //Dog类重写了虚方法 23 class Dog : Animal 24 { 25 public Dog(string name, string color, string kind, string favorite) 26 : base(name, color, kind) 27 { 28 this.Favorite = favorite; 29 } 30 //吃饭 31 public override void Have() 32 { 33 Console.WriteLine("我们要吃香喷喷的排骨啦!"); 34 } 35 } 36 37 //Cat类未重写虚方法 38 class Cat : Animal 39 { 40 public Cat(string name, string color, string kind, string favorite) 41 : base(name, color, kind) 42 { 43 this.Favorite = favorite; 44 } 45 } 46 47 static void Main(string[] args) 48 { 49 //创建一只狗和一只猫 50 Cat objCat = new Cat("球球儿", "黄色", "小花猫", "小鱼"); 51 Dog objDog = new Dog("棒棒", "黑色", "小黑狗", "排骨"); 52 //将子类对象添加的父类集合 53 List<Animal> list = new List<Animal>(); 54 list.Add(objCat); 55 list.Add(objDog); 56 //取出子类对象 57 foreach (Animal obj in list) 58 { 59 obj.Have(); 60 } 61 Console.ReadLine(); 62 } 63 64 //最终结果显示 65 //我们要吃饭啦! 66 //我们要吃香喷喷的排骨啦!
19.虚方法与抽象方法比较
虚方法 | 抽象方法 |
用virtual修饰 | 用abstract修饰 |
要有方法体,哪怕是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类都可以写 | 必须在抽象类中 |
20.object类自带的虚方法
Eauals()虚方法
对于字符串和值类型,能够自动比较是否相等
对于对象比较,必须重写override后才有意义
ToString()虚方法
对于值类型,返回变量值的字符串表示
对于对象,默认返回该对象的完全限定类型名(完全限定类型名:引用空间+类名),可根据需要重写
21.密封类sealed
当一个类使用sealed修饰后,该类不能被继承。
sealed对于保护知识产权起到一定作用,一定程度限制别人二次开发。
22.方法覆盖new
子类中的方法定义时使用new关键字覆盖父类中的同名方法
使用子类覆盖父类的方法后,子类对象调用该方法调用的是子类中new的方法
如果其他子类没有覆盖new父类的同名方法,其他子类对象调用此方法时仍然是父类中的方法
在控件开发中经常使用new关键字来覆盖父类的同名方法
1 //Dog覆盖了Introduce(),Cat未处理 2 abstract class Animal 3 { 4 public string Name { get; set; }//名字 5 public string Color { get; set; }//颜色 6 public string Kind { get; set; }//种类 7 public string Favorite { get; set; }//喜好 8 //父类构造函数 9 public Animal() { } 10 public Animal(string name, string color, string kind) 11 { 12 this.Color = color; 13 this.Name = name; 14 this.Kind = kind; 15 } 16 //自我介绍 17 public void Introduce() 18 { 19 string info = string.Format("这是父类的方法,我是漂亮的{0},我的名字叫{1},身穿{2}的衣服,我爱吃{3}!", 20 Kind, Name, Color, Favorite); 21 Console.WriteLine(info); 22 } 23 } 24 25 class Dog : Animal 26 { 27 public Dog(string name, string color, string kind, string favorite) 28 : base(name, color, kind) 29 { 30 this.Favorite = favorite; 31 } 32 public new void Introduce() 33 { 34 string info = string.Format("这是Dog类中的方法Hi! I am {0},My Name is {1}!", 35 Kind, Name); 36 Console.WriteLine(info); 37 } 38 } 39 40 class Cat : Animal 41 { 42 public Cat(string name, string color, string kind, string favorite) 43 : base(name, color, kind) 44 { 45 this.Favorite = favorite; 46 } 47 } 48 49 static void Main(string[] args) 50 { 51 //创建一只狗和一只猫 52 Cat objCat = new Cat("球球儿", "黄色", "小花猫", "小鱼"); 53 objCat.Introduce(); 54 Dog objDog = new Dog("棒棒", "黑色", "小黑狗", "排骨"); 55 objDog.Introduce(); 56 Console.ReadLine(); 57 } 58 59 //结果显示 60 //这是父类的方法,我是漂亮的小花猫,我的名字叫球球儿,身穿黄色的衣服,我爱吃小鱼! 61 //这是Dog类中的方法,Hi! I am 小黑狗,My Name is 棒棒!
23.面向对象三大特性简单总结
23.1封装 隐藏内部实现,稳定外部接口——>系统稳定性
23.2继承 子类继承父类成员,实现代码复用——>开发和维护效率
23.3多态 不同子类,对同一消息,做出不同反应——>系统扩展性
23.1 封装是把一个对象的属性和行为打包,继承就是动物都会呼吸,多态就是人用肺呼吸,鱼用鳃呼吸。封装的是字段、属性、方法。封装的好处:数据安全、内部修改保持稳定、提高重用性、分工合作、职责分明、方便构建大型复杂的系统。封装是面向过程到面向对象的最大的一个改变。
23.2 继承:去掉重复代码,可以实现多态,是侵入性很强的类关系,里氏替换原则
23.3 多态:相同的变量,相同的操作,但是不同的实现。方法重载、接口&实现、抽象类&实现、继承&实现。
23.4 抽象abstract:一方面子类都得有某个行为,另一方面子类中的各个行为又各不相同,可以在抽象abstract类里面定义一个抽象方法,在抽象方法里仅仅定义方法声明没有方法的具体实现,所有继承抽象类的子类必须override重写此抽象方法。抽象类没法直接实例化,只能new子类;面向抽象,只能用抽象里面的东西,如果有个性化操作(某个子类特有的),那就别抽象了,因为没有意义。
23.5接口:接口中方法不能具体实现,这点和抽象类类似,且不能写访问修饰符,全部默认public,接口可以包含属性、事件、索引器,不能包含字段、委托、类。实现接口需要显式实现接口的所有方法(子类中方法前不需要加override)。接口不能直接实例化,只能new实现该接口的子类。
23.6 如何选择接口和抽象类?
抽象类:父类+约束,父类的特性可以在抽象类中完成通用方法的实现。 【 :相当于 is a】
接口:纯粹的约束,只能约束,接口中所有的方法仅仅是声明、都不能实现。【:相当于 can do】
一个子类只能继承一个父类,但可以实现多个接口,这点上来讲接口实现更灵活。【单继承多实现】 抽象类毕竟还是一个类,只是某些内容不确定,例如手机基类,在抽象类中可以定义名称、用户等属性和Call()、Photo()等可以实现的共有方法以及抽象的什么操作系统的手机方法,而接口则是定义行为,形容一系列事物可以大致做什么。【子类都一样的,放在父类;子类都有但是相关之间不同,抽象一下;有的有有的没有,接口】【工作中接口用的更多,因为接口更简单灵活,除非有些共有的东西需要继承】
举例:门:属性有材质、猫眼、门铃 方法有开门()、关门()、报警() 抽象类:材质、开门()、关门() 接口:猫眼(运钞车也有猫眼,所以运钞车可以继承此接口) 接口:门铃 接口:报警(能报警的东西很多,例如说监控器、健康手表,所以这类东西都可以继承此接口)
23.7 虚方法virtual与抽象方法abstract【重写new 覆写override 重载overload】
虚方法可以在父类中默认实现,抽象方法不能在父类中实现,虚方法可以在子类中覆写也可以不覆写,抽象方法必须在子类中覆写。virtual、abstract、override可以一直覆写,不想被覆写,方法名前加sealed(密封:断子绝孙) base.() 调用直接父类的方法 this.()指定当前这个类型的实例的方法,this只能放在实例方法中,在子类构造函数中的this.属性,该属性是父类中的属性,除非在子类中重写new此属性,如果重写this指的是此类中的属性。