《C#高级编程(第6版)》第4章筆記第4章继 承

实现继承和接口继承
在面向对象的编程中,有两种截然不同的继承类型:实现继承和接口继承。

● 实现继承:表示一个类型派生于一个基类型,拥有该基类型的所有成员字段和函数。在实现继承中,派生类型的每个函数采用基类型的实现代码,除非在派生类型的定义中指定重写该函数的实现代码。在需要给现有的类型添加功能,或许多相关的类型共享一组重要的公共功能时,这种类型的继承是非常有效的。例如第31章讨论的Windows Forms类。第31章也讨论了基类System.Windows.Forms.Control,该类提供了常用Windows控件的非常复杂的实现代码,第31章还讨论了许多其他的类,例如System. Windows.Forms.TextBox和System.Windows.Forms.ListBox,这两个类派生于Control,并重写了函数,或提供了新的函数,以实现特定类型的控件。

● 接口继承:表示一个类型只继承了函数的签名,没有继承任何实现代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。例如,某些类型可以指定从接口System.IDisposable(详见第12章)中派生,从而提供一种清理资源的方法Dispose()。由于某种类型清理资源的方式可能与另一种类型的完全不同,所以定义通用的实现代码是没有意义的,此时就适合使用接口继承。接口继承常常被看做提供了一种契约:让类型派生于接口,来保证为客户提供某个功能。

多重继承
一些语言如C++支持所谓的"多重继承",即一个类派生于多个类。使用多重继承的优点是有争议的:一方面,毫无疑问,可以使用多重继承编写非常复杂、但很紧凑的代码,如C++ ATL库。另一方面,使用多重实现继承的代码常常很难理解和调试(这也可以从C++ ATL库中看出)。如前所述,使健壮代码的编写容易一些,是开发C#的重要设计目标。因此,C#不支持多重实现继承。而C#又允许类型派生于多个接口。这说明,C#类可以派生于另一个类和任意多个接口。更准确地说,因为System.Object是一个公共的基类,所以每个C#类(除了Object类之外)都有一个基类,还可以有任意多个基接口。

结构和类
定义结构和类可以总结为:

● 结构总是派生于System.ValueType,它们还可以派生于任意多个接口。

● 类总是派生于用户选择的另一个类,它们还可以派生于任意多个接口。

虚方法
把一个基类函数声明为virtual,该函数就可以在派生类中重写了
C#中虚函数的概念与标准OOP概念相同:可以在派生类中重写虚函数。在调用方法时,会调用对象类型的合适方法。在C#中,函数在默认情况下不是虚拟的,但(除了构造函数以外)可以显式地声明为virtual。这遵循C++的方式,即从性能的角度来看,除非显式指定,否则函数就不是虚拟的。而在Java中,所有的函数都是虚拟的。但C#的语法与C++的语法不同,因为C#要求在派生类的函数重写另一个函数时,要使用override关键字显式声明.
成员字段和静态函数都不能声明为virtual,因为这个概念只对类中的实例函数成员有意义。

隐藏方法

如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual 和 override,派生类方法就会隐藏基类方法,在C#中,应使用new关键字声明我们要隐藏一个方法.

调用函数的基类版本
C#有一种特殊的语法用于从派生类中调用方法的基类版本:base.<MethodName>()。
这个语法类似于Java,但Java使用关键字super而不是base。
注意,可以使用base.<MethodName>()语法调用基类中的任何方法,不必在同一个方法的重载中调用它。

抽象类和抽象函数

C#允许把类和函数声明为abstract,抽象类不能实例化,而抽象函数没有执行代码,必须在非抽象的派生类中重写。显然,抽象函数也是虚拟的(但也不需要提供virtual关键字,实际上,如果提供了该关键字,就会产生一个语法错误)。

密封类和密封方法
C#允许把类和方法声明为sealed。对于类来说,这表示不能继承该类;对于方法来说,这表示不能重写该方法。

注意:

Java开发人员可以把C#中的sealed当作Java中的final。

在把类或方法标记为sealed时,最可能的情形是:如果要对库、类或自己编写的其他类进行操作,则重写某些功能会导致错误。也可以因商业原因把类或方法标记为sealed,以防第三方以违反注册协议的方式扩展该类。但一般情况下,在把类或方法标记为sealed时要小心,因为这么做会严重限制它的使用。即使不希望它能继承一个类或重写类的某个成员,仍有可能在将来的某个时刻,有人会遇到我们没有预料到的情形。.NET基类库大量使用了密封类,使希望从这些类中派生出自己的类的第三方开发人员无法访问这些类。例如string就是一个密封类。


派生类的构造函数
默认的Nevermore60Customer构造函数甚至不知道存在这个字段。唯一知道这个字段的是GenericCustomer的其他成员,即如果对name进行初始化,就必须在GenericCustomer的某个构造函数中进行。无论类层次结构有多大,这种情况都会一直延续到最终的基类System.Object上。
构造函数的调用顺序是先调用System.Object,再按照层次结构由上向下进行,直到到达编译器要实例化的类为止。还要注意在这个过程中,每个构造函数都初始化它自己的类中的字段。这是它的一般工作方式,在开始添加自己的构造函数时,也应尽可能遵循这个规则。

接口
声明接口在语法上与声明抽象类完全相同,但不允许提供接口中任何成员的执行方式。一般情况下,接口中只能包含方法、属性、索引器和事件的声明。
不能实例化接口,它只能包含其成员的签名。接口不能有构造函数(如何构建不能实例化的对象?)或字段(因为这隐含了某些内部的执行方式)。接口定义也不允许包含运算符重载,但这不是因为声明它们在原则上有什么问题,而是因为接口通常是公共契约,包含运算符重载会引起一些与其他.NET语言不兼容的问题,例如与VB的不兼容,因为VB不支持运算符重载。

派生的接口
接口可以彼此继承,其方式与类的继承相同。

申明

非源创博文中的内容均收集自网上,若有侵权之处,请及时联络,我会在第一时间内删除.再次说声抱歉!!!

博文欢迎转载,但请给出原文连接。

原文地址:https://www.cnblogs.com/Athrun/p/1519327.html