目录
其实这是哲学的思维方式,所谓哲学就是建立事实基础上,是人类对世界的思考和认识。要理解抽象类就必须要有一定的编程经验,就好像要理解哲学就需要有一定的生活经验。跟一个没有大量编程经验的人将设计模式那也是扯蛋!所以作为一个新手,特别是没有面向对象编程经验的来说,不理解抽象类是很正常的,等你有了一定的编程经验,你自然而然就会理解了。
一、概念区分
先看看MSDN的关于抽象类和虚方法的解释:
使用 abstract 关键字可以创建仅用于继承用途的类和类成员,即定义派生的非抽象类的功能。
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。例如,此方法可被任何继承它的类重写。
说说抽象类的理解吧:
既然是抽象类,那么就是对事物的抽象描述,它描述的是个体的共性。那马这种动物来说,我们所说的马就是一个抽象类。世界上存在很多种马,白马,黑马,红马......如果没有抽象的概念,我们就没法获得世界上所有马,因为我们要说马的时候,必须指定是哪种马!但是我们其实是有抽象的概念的,我们定义了马这样的一个概念,用来指代世界上所有的马。但马在这个世界上并不是真实存在的,你所能看见的马一定是某一种类型的马!
所以说,抽象类就是这样一种类,描述了一种事物的共性,它不能实例化,只能通过它的子类实例化。
抽象方法:抽象方法一定是抽象类里面的,抽象的方法没有主体,就是没有实现代码,它的实现是由子类实现的。如果一个抽象类里面全是抽象方法的画,那么这个类和接口的功能基本就是一致,而抽象类和接口不一样的地方就在于抽象类可以有非抽象的方法。
还是以马类来说:
//一个抽象的马类
public abstract class 马类
{
//长毛这个方法是抽象的方法,因为它的实现
//必须是具体的那种马去实现的
public abstract void 长毛();
//消化这个方法不是抽象的,所有的马
//都按这个方法去消化东西
public void 消化()
{
Console.WriteLine("消化食物");
}
}
public class 红马 : 马类
{
public override void 长毛()
{
Console.WriteLine("我长的是红毛");
}
}
public class 白马 : 马类
{
public override void 长毛()
{
Console.WriteLine("我长的是白毛");
}
}
说完了抽象,说说虚方法。
标记为虚方法的方法,可以在子类被重写。也就说子类可以变异。还是马类为例:
public abstract class 马类
{
//长毛这个方法是抽象的方法,因为它的实现
//必须是具体的那种马去实现的
public abstract void 长毛();
//消化这个方法是虚方法,所有的马
//都按这个方法去消化东西,也可以变异
public virtual void 消化()
{
Console.WriteLine("1小时消化1千克食物");
}
}
public class 红马 : 马类
{
public override void 长毛()
{
Console.WriteLine("我长的是红毛");
}
//在这里变异了,消化能力超强
public override void 消化()
{
Console.WriteLine("1小时消化1吨食物");
}
}
二、总结
先说说区别:
1、虚方法必须有实现部分,抽象方法不可以有实现部分;
2、虚方法可以在派生类中重写也可以不重写,抽象方法必须在派生类中重写
3、虚方法可以在任何非密封类中声明,抽象方法只能在抽象类中声明。
4、如果类包含抽象方法,那么该类也必须为抽象的,不能实例化。
相比而言,虚方法倾向于代码复用,抽象方法更类似一种规约来约束子类必须实现某方法。
三、二者有些相似,是否有同时存在的必要?
举个例子(未必恰当、只为说明问题):非常容易理解二者同时存在的意义!!!
比如有个基类“动物”;两个子类“狮子”、“青蛙”。
狮子捕猎:锁定目标、用牙齿和利爪抓获;
狮子说话:噢呜;
青蛙捕猎:锁定目标、用舌头抓获;
青蛙说话:呱呱;
对于捕猎,他们有共性也有区别:
所以就可以把捕猎声明为虚方法,基类里实现共性部分、各子类实现个性部分;
对于说话,完全不同,但是又必须让他们说话——否则成植物了,呵呵:
所以就可以把说话声明为抽象方法,基类只声明此方法来作为约束,强制子类实现。