在我研读分词器源码的过程中,又碰到了以前还未完全弄明白的抽象方法与虚方法。下面我将结合源码里面的内容,重新来学习一些抽象方法与虚方法的区别。
下面是分词器模块中的一部分类的关系图。
TokenStream类是所有类的父类。TokenStream类里面有两个方法,看下面的代码:
abstract public class TokenStream
{
///<summary>
///返回语汇单元流中的下一个词元,或者是空,也就是结束,返回EOS
///Returns the next token in the stream, or null at EOS.
///</summary>
abstract public Token Next();
///<summary>
///释放语汇单元流所使用的资源
///</summary>
public virtual void Close()
{
}
}
Next是一个抽象方法,Close是一个虚方法。通过上面的代码,我们就可以看出一些区别:
抽象方法:
1.以abstract修饰,abstract在Public的前面。没有方法体,在小括号后面直接跟一分号就结束,没有大括号。
2.有抽象方法的类一定是抽象类,我们可以看到TokenStream类是一个抽象的类。但抽象类中可以有非抽象的方法,比如Close就是非抽象的方法。
虚方法:
1.以virtual修饰,virtual在Public的后面。有方法体,在小括号的后面跟着一对大括号。此大括号里可以有方法的实现,也可以没有,此处为没有实现。
我们再来看看TokenStream类的一个子类TokenFilter,它的代码如下:
abstract public class TokenFilter : TokenStream
{
///<summary>
///需要传过来的处理的TokenStream
///The source of tokens for this filter.
///</summary>
protected TokenStream input;
///<summary> Close the input TokenStream. </summary>
public override void Close()
{
input.Close();
}
可以看到此类实现了虚方法Close,但是却找不到抽象方法Next的踪迹。这是为什么呢,不是说子类一定要实现抽象方法,不一定要实现虚方法的吗,难道有错?。我们再来看看TokenFilter这个类,需要注意,它前面有一个abstract来修饰,这说明它是一个抽象类。所以一切就明白了。确切的来说:
非抽象的子类一定要实现父类的抽象方法。也就是子类一定要实现父类的抽象方法,如果没有实现,那么这个子类一定也是个抽象类,那么父类的抽象方法就由这个子类的非抽象子类去实现。
子类不一定要实现父类的虚方法,不管这个类是不是抽象类。
我们再来看看TokenFilter的子类LowerCaseFilter类,它的代码如下:
public class LowerCaseFilter : TokenFilter
{
/// <summary>
/// Initializes a new instance of the LowerCaseFilter class.
/// </summary>
/// <param name="ts">Token stream to read from.</param>
public LowerCaseFilter(TokenStream ts)
{
input = ts;
}
/// <summary>
/// Returns the next token from the stream.
/// </summary>
/// <returns>The next token or null if EOS.</returns>
public override Token Next()
{
Token t = input.Next();
if (t == null)
return null;
t.TermText = t.TermText.ToLower();
return t;
}
}
因为抽象方法是强制要求非抽象子类必须实现,所以不能用Sealed来修饰抽象方法,因为Sealed表示这个方法不能被继承,而抽象方法又必须需要子类来实现。
最后来总结一下两者的区别:
1.抽象方法与虚方法的定义方式不同,抽象方法是用abstract来修饰,虚方法是用virtual修饰。抽象方法是小括号后面加一个分号,而虚方法是小括号后面还有大括号,大括号里面可以有方法的实现内容,也可以没有。
2.有抽象方法的类一定是抽象类,抽象类中的方法不一定非要是抽象方法,也可以有其他的非抽象方法。而普通类中也可以有虚方法求。
3.非抽象的子类一定要实现父类中的抽象方法,而对于虚方法,子类可以实现,也可以不实现。
4.抽象方法不能与Sealed关键字一起使用。
5.子类实现抽象方法或虚方法,需要在前面加上override关键字。