参考
简单易懂的解释c#的abstract和virtual的用法和区别
一、abstract
先来看abstract方法,顾名思义,abstract方法就是抽象方法。抽象方法就是没有实现的,必须是形如:
public abstract void Init();
拥有抽象方法的类必须修饰一个abstract关键字从而变成一个抽象类;但是反过来,抽象类里面不一定要有抽象方法,比如我写了一个非抽象类,但是这个类我不想让人直接实例化,而只让人继承,我就可以把他变成一个抽象类,虽然他里面并没有抽象方法。形如:
abstract class TestAbstractSuper
- 抽象类不能被实例化,只能被继承。
- 抽象类的子类必须实现每个抽象方法。
- 抽象类里面除了可以有抽象方法以外,也可以有普通的方法。
- 抽象类的构造函数可以省略,编译器会自动加上,但是不能是一个抽象方法,而只能是一个普通的构造函数。
小结:简单概括一下,抽象类不可以直接实例化,他可以有n个(n>=0)抽象方法,这些抽象方法子类必须实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestAppAllHere
{
abstract class TestAbstractSuper
{
public TestAbstractSuper()
{
Debug.WriteLine("这是父类的构造方法");
}
public abstract void Init();
public void Hello()
{
Debug.WriteLine("这是父类的非抽象方法");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestAppAllHere
{
class TestAbstractSub:TestAbstractSuper
{
public TestAbstractSub()
{
Debug.WriteLine("这是子类的构造方法");
}
public override void Init()
{
Debug.WriteLine("这是子类重写的方法");
}
}
}
TestAbstractSub sub = new TestAbstractSub();
sub.Init();
sub.Hello();
这是父类的构造方法
这是子类的构造方法
这是子类重写的方法
这是父类的非抽象方法
二、virtual
- 声明了virtual的方法无需去改动类的声明,他只在此方法上起到影响。
- 只有virtual的方法可以被子类override。
- 子类可以不override父类的virtual方法,这种情况下他就像普通的父类方法一样。
小结:简单概括一下,virtual关键字就是告诉子类,此方法可以被override,但非强制。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestAppAllHere
{
class TestVirtualSuper
{
public TestVirtualSuper()
{
Debug.WriteLine("这是父类的构造方法");
}
public virtual void Init()
{
Debug.WriteLine("这是父类的虚拟方法");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestAppAllHere
{
class TestVirtualSub:TestVirtualSuper
{
public TestVirtualSub()
{
Debug.WriteLine("这是子类的构造方法");
}
//___________________没有重写这个虚拟方法也是可以照常运行的,会调用父类的虚拟方法_________________________
//___________________重写了之后父类的虚拟方法不会运行,而是重写,当然可以用base.来调用父类的方法__________
public override void Init()
{
//base.Init();
Debug.WriteLine("这是子类的重写方法");
}
}
}
TestVirtualSub sub = new TestVirtualSub();
sub.Init();
这是父类的构造方法
这是子类的构造方法
这是子类的重写方法
三、C#.NET里面抽象类和接口有什么区别
如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。
看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该定义,关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man,都继承Person,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。
但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个PersonHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。
总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。
再者,我认为接口和抽象类的另一个区别在于,抽象类和它的子类之间应该是一般和特殊的关系,而接口仅仅是它的子类应该实现的一组规则。(当然,有时也可能存在一般与特殊的关系,但我们使用接口的目的不在这里)如,交通工具定义成抽象类,汽车、飞机、轮船定义成子类,是可以接受的,因为汽车、飞机、轮船都是一种特殊的交通工具。再譬如Icomparable接口,它只是说,实现这个接口的类必须要可以进行比较,这是一条规则。如果Car这个类实现了Icomparable,只是说,我们的Car中有一个方法可以对两个Car的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它。
所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
四、sealed
参考 C#中sealed关键字
当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。类似于Java中final关键字。
网友评论