-
C#教程之C#面向对象之继承
试听地址 https://www.xin3721.com/eschool/CSharpxin3721/
一、继承
什么是继承?继承是两个或多个类之间存在的依赖关系,其中被继承的类称为父类或基类,继承的类称为子类或派生类。在继承关系中,父类是对子类的共性提取,子类是对父类的扩展。
1 /// <summary> 2 /// 文字 3 /// </summary> 4 public class Word 5 { 6 /// <summary> 7 /// 内容 8 /// </summary> 9 public string Content { get; set; } 10 /// <summary> 11 /// 大小(单位B) 12 /// </summary> 13 public int Size { get; set; } 14 15 public Word() { } 16 public Word(string content, int size) 17 { 18 this.Content = content; 19 this.Size = size; 20 } 21 } 22 /// <summary> 23 /// 图片 24 /// </summary> 25 public class Picture 26 { 27 /// <summary> 28 /// 内容 29 /// </summary> 30 public string Content { get; set; } 31 /// <summary> 32 /// 大小(单位B) 33 /// </summary> 34 public int Size { get; set; } 35 /// <summary> 36 /// 地址 37 /// </summary> 38 public string Path { get; set; } 39 40 public Picture() { } 41 public Picture(string content, int size, string path) 42 { 43 this.Content = content; 44 this.Size = size; 45 this.Path = path; 46 } 47 48 /// <summary> 49 /// 图片存储到文件中,并为Path赋值 50 /// </summary> 51 public void StoreToFile() 52 { 53 54 } 55 }
上面设计的文字类和图片类中存在代码冗余,为了去除冗余,我通过提取共性的方式引入了第三个类,并让其他两个类继承它,代码如下:
1 /// <summary> 2 /// 信息 3 /// </summary> 4 public class Information 5 { 6 /// <summary> 7 /// 内容 8 /// </summary> 9 public string Content { get; set; } 10 /// <summary> 11 /// 大小(单位B) 12 /// </summary> 13 public int Size { get; set; } 14 15 public Information() { } 16 public Information(string content, int size) 17 { 18 this.Content = content; 19 this.Size = size; 20 } 21 } 22 /// <summary> 23 /// 文字 24 /// </summary> 25 public class Word : Information 26 { 27 public Word() { } 28 public Word(string content, int size) 29 { 30 this.Content = content; 31 this.Size = size; 32 } 33 } 34 /// <summary> 35 /// 图片 36 /// </summary> 37 public class Picture : Information 38 { 39 /// <summary> 40 /// 地址 41 /// </summary> 42 public string Path { get; set; } 43 44 public Picture() { } 45 public Picture(string content, int size, string path) 46 { 47 this.Content = content; 48 this.Size = size; 49 this.Path = path; 50 } 51 52 /// <summary> 53 /// 图片存储到文件中,并为Path赋值 54 /// </summary> 55 public void StoreToFile() 56 { 57 58 } 59 } 60 /// <summary> 61 /// 实现对象 62 /// </summary> 63 public class RealizeObject 64 { 65 public void Realize() 66 { 67 //Word类和Picture类继承Information类后,Information类的Content和Size属性就像Word类和Picture类的属性一样 68 Word word = new Word("book", 4); 69 Picture picture = new Picture("", 0, @"C:\Users\Images\"); 70 Information info = new Information("this is Info", 12); 71 } 72 }
通过继承连接文字/图片类和它们提取共性的信息类,实现了代码的复用性,后期如果加上音频类和视频类也可以通过继承复用信息类的代码,而不用重复编写Content和Size属性。
继承的规则:
1、子类可以继承除了父类构造函数之外的所有非私有成员。
2、子类的任意构造函数调用之前会先调用父类的默认构造函数。
3、子类的可访问性不能高于父类,因为这样会强制父类的可访问性同子类的可访问性(比如Word用public修饰,Information用internal修饰)。
4、C#不允许类的多重继承,即一个类只能有一个直接父类(继承引号符后面只能写一个类)。
根据继承规则二,总结继承中代码的执行顺序:执行变量的初始化表达式 → 执行父类的(默认)构造函数 → 调用类型自己的构造函数
1 public class A 2 { 3 public To t = new To("TO A"); 4 5 public A() 6 { 7 Console.WriteLine("A"); 8 } 9 } 10 public class B : A 11 { 12 public To t = new To("TO B"); 13 14 public B() 15 { 16 Console.WriteLine("B"); 17 } 18 } 19 public class C : B 20 { 21 public To t = new To("TO C"); 22 23 public C() 24 { 25 Console.WriteLine("C"); 26 } 27 } 28 public class To 29 { 30 public To(string msg) 31 { 32 Console.WriteLine(msg); 33 } 34 } 35 public class RealizeObject 36 { 37 public void Realize() 38 { 39 C c = new C(); 40 //输出结果是: 41 //TO C 42 //TO B 43 //TO A 44 //A 45 //B 46 //C 47 } 48 }
二、C#关键字:base
继承的规则一说明子类无法使用父类的构造函数,所以我在文字类和图片类中创建了自己的构造函数。继承的规则二说明子类只能隐式地调用父类的默认构造函数,而无法调用父类的非默认构造函数,即无法复用父类的非默认构造函数,所以可以通过base关键字使子类的构造函数自定义调用父类的非默认构造函数。下面修改文字类和图片类使其复用父类的非默认构造函数:
1 /// <summary> 2 /// 文字 3 /// </summary> 4 public class Word : Information 5 { 6 public Word() { } 7 public Word(string content, int size) : base(content, size); 8 } 9 /// <summary> 10 /// 图片 11 /// </summary> 12 public class Picture : Information 13 { 14 /// <summary> 15 /// 地址 16 /// </summary> 17 public string Path { get; set; } 18 19 public Picture() { } 20 public Picture(string content, int size, string path) 21 : base(content, size) 22 { 23 this.Path = path; 24 } 25 26 /// <summary> 27 /// 图片存储到文件中,并为Path赋值 28 /// </summary> 29 public void StoreToFile() 30 { 31 32 } 33 }
base关键字除了可以复用父类非默认构造函数之外,还可以复用父类的其他非私有成员(见C#多态)。
总结:base关键字的使用方式同this关键字一样,区别在于this关键字指向本类,base关键字指向父类。
三、C#关键字:sealed
sealed关键字可以防止被继承或者被重写。
1 /// <summary> 2 /// 视频类(不能被其他类继承) 3 /// </summary> 4 public sealed class Video : Information { }
注:sealed在防止被继承时多用于工具类。
sealed防止被重写(见C#多态)。
四、C#关键字:protected
protected是专门用于继承中的访问修饰符,修饰在父类的成员上使其成员可被本类及其子类访问。
注:protected多用于修饰父类的方法。
访问修饰符直白对比:对全世界开放,使用public;只对本国开放,使用internal;只对家族开放,使用protected;只有自己知道,使用private。
五、类型之间的关系:包含
C#五大类型(类、接口、委托、枚举、结构)之间的相互嵌套即包含关系。既可以包含已定义类型也可以直接在被包含类型内定义类型。
包含的作用同继承一样也是提高代码的复用性。
1 /// <summary> 2 /// 洗衣机类 3 /// </summary> 4 public class WashingMachine 5 { 6 7 } 8 /// <summary> 9 /// 房间类 10 /// </summary> 11 public class House 12 { 13 /// <summary> 14 /// 房间类包含已定义的洗衣机类 15 /// </summary> 16 public WashingMachine washingMachine { get; set; } 17 18 /// <summary> 19 /// 直接在房间类中定义空调类 20 /// </summary> 21 public class AirConditioner 22 { 23 24 } 25 26 /// <summary> 27 /// 直接在房间类中定义性别枚举 28 /// </summary> 29 public enum Sex { man, woman } 30 }