深入浅出OOP(四): 多态和继承(抽象类)
在本文中,我们讨论OOP中的热点之一:抽象类。抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样。本文中我们会通过代码来实现抽象类,并一一进行解析。
Abstract Classes
在微软的MSDN中,对抽象类有如下的定义:
用abstract 关键字可定义抽象类,要求其子类必须实现抽象类的函数、属性等。抽象类不可被实例化。抽象类提供了统一的定义,用于其不同子类直接共享数据、函数。 抽象类也可定义抽象函数。
Abstract Classes实战
在Visual Studio中添加Console程序,并命名为“InheritanceAndPolymorphism
”,添加ClassA.cs,添加抽象类ClassA。
using System; namespace InheritanceAndPolymorphism
{
public abstract class ClassA
{ } /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}
}
编译报错:
Compile time error: Cannot create an instance of the abstract class or interface 'InheritanceAndPolymorphism.ClassA'
结论:无法用new关键字来实例化一个抽象类。
Abstract Class的非抽象函数
给抽象类ClassA添加一些非抽象函数的代码:
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ }
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassA classA = new ClassA();
Console.ReadKey();
}
}
编译,依然报错。 抽象类无论是否有抽象、非抽象函数,均无法通过new关键字来实例化。
Abstract Class作为基类
我们把抽象类作为基类,添加ClassB—使之继承自ClassA。
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ }
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA
/// </summary>
public class ClassB:ClassA
{ } /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译的结果:不再报错。
结论:一个类可以继承自abstract 修饰的抽象类,且可被new关键字初始化。
Abstract Class的非抽象函数声明
在ClassA中声明YYY函数--无函数体。
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ } public void YYY();
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{ } /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译,结果报错:
Compile time error: 'InheritanceAndPolymorphism.ClassA.YYY()' must declare a body because it is not marked abstract, extern, or partial
结论是需要对YYY添加函数体,或者添加abstract的修饰符。
Abstract Class的抽象函数声明
在ClassA的YYY前,添加abstract修饰符。
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ } abstract public void YYY();
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{ } /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译结果,报错:
Compiler error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'
结论:我们在abstract 类中声明了一个
abstract 的函数,但是并未在其子类ClassB中实现其内容;当使用new关键字初始化ClassB的时候则会报错----无法使用new关键字初始化一个
abstract类。
子类继承实现抽象函数
在子类中添加YYY的实现。
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ } abstract public void YYY();
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public void YYY()
{ }
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译结果,报错:
Compile time error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()' Compile time warning: 'InheritanceAndPolymorphism.ClassB.YYY()' hides inherited member 'InheritanceAndPolymorphism.ClassA.YYY()'.
结论:要使得子类继承基类的YYY函数,需要用到override关键字,然后才可以用new关键字实例化ClassB。
非抽象类的抽象函数
我们再看看这些代码:
/// <summary>
/// Abstract class ClassA
/// </summary>
public class ClassA
{
public int a;
public void XXX()
{ } abstract public void YYY();
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override void YYY()
{ }
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译,结果报错:
Compiler error: 'InheritanceAndPolymorphism.ClassA.YYY()' is abstract but it is contained in non-abstract class 'InheritanceAndPolymorphism.ClassA'
结果分析:声明abstract的函数,必须同时声明类为
abstract。
abstract 的函数不能同时添加static或virtual关键字。
抽象基类函数
/// <summary>
/// Abstract class ClassA
/// </summary>
public abstract class ClassA
{
public int a;
public void XXX()
{ } abstract public void YYY();
} /// <summary>
/// Derived class.
/// Class derived from abstract class ClassA.
/// </summary>
public class ClassB:ClassA
{
public override void YYY()
{
base.YYY();
}
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
Console.ReadKey();
}
}
编译,结果报错:
Compile time error : Cannot call an abstract base member: 'InheritanceAndPolymorphism.ClassA.YYY()'
结果分析:ClassB中无法使用base调用基类的abstract函数--因为其不存在。
最后一个问题,可否在抽象类中添加sealed关键字,结果是不可以。
抽象类不能添加sealed、static类修饰符的。
结论
通过下面几点,归纳一下本文的结论。
- 无法使用new来实例化
abstract 抽象类
abstract 抽象类可以有子类,其子类实现抽象方法后,可被new实例化对象
如声明了
abstract 的函数,则必须声明
abstract 的类
当override抽象基类,无法修改基类函数的签名
abstract函数,无法同时添加static、virtual关键字
abstract 类无法被声明为sealed、static类
原文链接:Diving in OOP (Day 4): Polymorphism and Inheritance (All About Abstract Classes in C#)
深入浅出OOP(四): 多态和继承(抽象类)的更多相关文章
- 深入理解OOP(四): 多态和继承(抽象类)
在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. 深入理解OOP(一):多态和继承(初期绑定 ...
- 深入理解OOP(二):多态和继承(继承)
本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...
- 深入理解OOP(三):多态和继承(动态绑定和运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...
- 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)
在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...
- 深入浅出OOP(六): 理解C#的Enums
MSDN定义:枚举类型(也称为枚举)为定义一组可以赋给变量的命名整数常量提供了一种有效的方法. 例如,假设您必须定义一个变量,该变量的值表示一周中的一天. 该变量只能存储七个有意义的值. 若要定义这 ...
- 深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)
访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类.类成员函数.类成员变量进行访问控制.同时,访问控制符也是语法保留关键字,用于封装组件. Public, Private, Protec ...
- 深入浅出OOP(二): 多态和继承(继承)
本文是深入浅出OOP第二篇,主要说说继承的话题. 继承的介绍 在OOP中,继承有如下的定义: 继承是一种OOP的机制,用于派生继承预定义的类 在这个继承关系中,预定义的类是基类,新类是子类 继承常常用 ...
- python开发面向对象基础:接口类&抽象类&多态&钻石继承
一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实 ...
- OOP面向对象 三大特征 继承封装多态
OOP面向对象 ----三大特征 继承封装多态 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构 ...
随机推荐
- smarty模板的安装配置
第一步:下载Smarty模版源码包了 百度一下“Smarty下载”,下载最新版本的Smarty模版第二部:解压缩,将下载好的Smarty包解压缩 右键->解压到当前文件夹...你懂的 ...
- Select查询语句2
一.模糊查询 1.语法结构 select*from table_name where column like '%context%' 在使用like运算符时如果不使用通配符“%”,则like的作用与= ...
- ASP.NET 创建网站地图
很多个人站长会使用工具来生成自己网站的站点地图,这样做的缺点在于网站的 sitemap 不能及时的得到更新.当我们发表了一篇新文章时,应该对网站的地图进行更新,并通知搜索引擎网站地图已经发生了改变! ...
- 内存屏障(Memory barrier)-- 转发
本文例子均在 Linux(g++)下验证通过,CPU 为 X86-64 处理器架构.所有罗列的 Linux 内核代码也均在(或只在)X86-64 下有效. 本文首先通过范例(以及内核代码)来解释 Me ...
- js判断访问终端
//判断访问终端 var browser={ versions:function(){ var u = navigator.userAgent, app = navigator.appVersion; ...
- 常用linux指令
删除:rm -rf -r 就是向下递归,不管有多少级目录,一并删除 -f 就是直接强行删除,不作任何提示的意思 压缩解压:tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向 ...
- 如何断开所有SQL Server所有的连接
方法1: 执行以下脚本 01.declare @sql varchar(100) 02. 03.while 1=1 04.begin 05. 06.select top 1 ...
- js原型
1.js基本类型和对象类型 js的简单类型包括数字(其中NaN为数字类型).字符串(类似'A'为字符,js没字符类型).布尔值.null值和undefined值.其他所有的值都是对象.数字.字符串和布 ...
- android studio view.setId报错
自定义控件设置id的时候会报错,如:view.setId(100); 解决方法: 方案一:通过调用View.generateViewId()作为setId的参数,但此方案不是最佳方案,因为View.g ...
- noip2014-day1-t2
题目描述:无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...