在本文中,我们讨论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#)

译文链接:http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Day-Polymorphism-and-Inheritance-All.html

深入理解OOP(四): 多态和继承(抽象类)的更多相关文章

  1. 深入理解OOP(三):多态和继承(动态绑定和运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...

  2. 深入理解OOP(二):多态和继承(继承)

    本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...

  3. 深入浅出OOP(四): 多态和继承(抽象类)

    在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. Abstract Classes 在微软的 ...

  4. 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)

    在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...

  5. PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)

    PHP面向对象三大特点学习 学习目标:充分理解抽象.封装.继承.多态   面象对向的三大特点:封装性.继承性.多态性 首先简单理解一下抽象:我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和 ...

  6. Java面向对象理解_代码块_继承_多态_抽象_接口

    面线对象: /* 成员变量和局部变量的区别? A:在类中的位置不同 成员变量:在类中方法外 局部变量:在方法定义中或者方法声明上 B:在内存中的位置不同 成员变量:在堆内存 局部变量:在栈内存 C:生 ...

  7. python开发面向对象基础:接口类&抽象类&多态&钻石继承

    一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实 ...

  8. OOP面向对象 三大特征 继承封装多态

    OOP面向对象 ----三大特征 继承封装多态 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构 ...

  9. 重新理解JS的6种继承方式

    写在前面 一直不喜欢JS的OOP,在学习阶段好像也用不到,总觉得JS的OOP不伦不类的,可能是因为先接触了Java,所以对JS的OO部分有些抵触. 偏见归偏见,既然面试官问到了JS的OOP,那么说明这 ...

随机推荐

  1. Nginx问题定位之监控进程异常退出

    nginx在运行过程中是否稳定,是否有异常退出过?这里总结几项平时会用到的小技巧. 1. 在error.log中查看是否有signal项,如果有,看看signal是多少. 比如,这是一个异常退出的情况 ...

  2. n枚硬币问题(找假币)

    问题描述: 在n枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重.可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币. 解题思路: ...

  3. 003.同时Ping多个IP(select实现IO复用,信号计时),ping程序升级版

    写这个的目的主要是为了以后的方便: 1.信号计时函数的使用 2.ip头的构建和icmp头的构建 3.selec函数t的用法 代码实现: /src/ping.h /* * ping.h * * Crea ...

  4. web报表移动端如何进行移动设备绑定与撤销

    场景需求描述 为了增强移动端的登录机制验证,保证数据的安全性,报表工具FineReport提供了移动设备绑定的功能,每个系统用户在使用移动端连接系统的时,需要管理员授权,将用户的移动设备与系统绑定起来 ...

  5. Eclipse汉化后怎么改回英文版(可切换中英文)

    Eclipse汉化后怎么改回英文版(可切换中英文) 很多朋友将MyEclipse汉化后还想改回英文的,其实只要修改MyEclipse的配置文件就可以了,这里我以MyEclipse7.0为例演示一下如何 ...

  6. win10 右键菜单添加使用gvim打开方式

    ①打开注册表编辑器,开始-->运行-->regedit ②定位到:HKEY_CLASSSES_ROOT---> * --->Shell,在Shell 上右击,新建---> ...

  7. Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组

    题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列. 解法:首先要得出定位方法,即知道某个排列是第几个排列.比如 (0, 1, 2), (0, ...

  8. poj3635Full Tank?[分层图最短路]

    Full Tank? Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7248   Accepted: 2338 Descri ...

  9. java io (一)

    对于文件内容的操作主要分为两大类 分别是:字符流 字节流 其中,字符流有两个抽象类:Writer   Reader 其对应子类FileWriter和FileReader可实现文件的读写操作 Buffe ...

  10. MYSQL数据库的操作

    Mysql的连接方式: 1.原生函数:mysql_connect($server,$username,$password);   //打开一个到Mysql服务器的连接 mysql_select_db( ...