本节书摘来自异步社区《.net程序员面试秘笈》一书中的第1章,面试题10,作者: 张云翯, 更多章节内容可以访问云栖社区“异步社区”公众号查看。
.net程序员面试秘笈
【考点】抽象类的理解,抽象类和接口的区别。
【出现频率】
【解答】
接口和抽象类非常相似,两者都无法实例化,并且未实现部分都由派生类实现,其应用模型如图1.14所示。
结合图1.14可知,接口与抽象类的主要区别有以下几点:
(1)抽象类只能派生类,而接口可以派生类和结构。
(2)抽象类的派生类也可以是抽象类,即抽象成员在派生类中不一定被完全实现。而接口要求其派生类或结构必须完全实现其成员。
(3)抽象类可以包含已经实现的成员,可以包含字段,而接口只包含未实现的成员,不能包含字段。并且接口及所含成员必须为public访问级别。
(4)类只能继承一个抽象类,但可以继承(实现)多个接口。

在具体的程序设计中,抽象类和接口的取舍应视程序的需要而定。抽象类可以用于归纳一组相似的、有共同特性的类,然后将这些类共同的成员提取到抽象类中,使抽象类作为这组类的基类。这样做到了代码的复用,不但节约了代码量,也减轻了维护的复杂度。然后将这组类中相似的方法或属性提取到抽象类中,成为抽象类的抽象成员,不提供具体实现,由这组类自己完成不同的实现。
说明:
抽象类的应用非常类似于网页制作中的css外部样式文件,大量风格相同的页面可以共用这个css文件,并且在页面中可以对部分css属性进行改写。
而接口是一组类的功能集合,也可以说是一组类的协定集合,这组类负责实现这些功能,可以说接口内含的成员都是抽象的。类可以实现多个接口,这样可将意图和实现分离,接口可以暴露给其他程序直接使用,并且可以很方便地进行功能的扩展。两者的应用对比如图1.14所示。
本例以computer为接口,通过pca类和pcb类实现该接口的功能。在ch01目录下新建一个程序文件,并命名为abstract.cs,编写代码如程序1.11所示。
在命令行下编译abstract.cs后,执行abstract程序,其效果如图1.15所示。
https://yqfile.alicdn.com/815a6d43015ae8430def24d12763e6fae330d9d7.png" >
本例代码中声明了名为person的抽象类,类体中声明了两个抽象成员(1个方法和1个属性),jacky类和femal类继承了person类。而femal类只实现了抽象属性,所以female必须仍然是抽象类,并且编写了mariah类继承female类,mariah类实现了所继承的抽象方法。而jacky类完全实现了person类的抽象成员,所以jacky类可以不是抽象类,可以创建实例。
程序运行时,创建jacky类的实例a,并直接输出其_msg字段,还调用了a的getname方法,并访问了ismale属性。然后创建mariah类的实例b,并进行相同的操作。从程序结果中可看出,person抽象类的_msg字段为所有派生类的可复用字段,是派生类共同的部分。只有完全实现了person类抽象成员的类才可以不是抽象类,如jacky类,而没有完全实现的类如female类仍然为抽象类。
【分析】
抽象类是一种用abstract关键字修饰的类,这种类仅用于被继承。类似于接口,抽象类无法创建实例,而类体可以声明多个未实现的抽象成员,这些成员由继承此类的派生类实现。其编写方法如以下代码所示:
可见,抽象类的类体中可包含实现的成员,而未实现的成员为抽象成员。抽象方法或属性本身就是隐性的virtual,所以派生类实现抽象方法或属性必须使用override关键字。继承抽象类的类如果没有完全实现抽象成员,仍然只能是抽象类,即派生的非抽象类必须完全实现抽象成员。抽象类也可以实现接口,这时抽象类必须实现所有的接口成员,也可以将继承的接口成员映射至抽象成员,并由其派生类来实现。
抽象类的抽象成员不能使用virtual或static修饰。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。