抽象方法和虚方法有什么区别?在哪些情况下建议使用抽象或虚方法?哪种方法是最佳的?
抽象方法是没有实现的方法,必须在子类中实现,而虚方法有默认实现但可以被覆盖。如果希望强制子类实现特定方法,则应该使用抽象方法,如果希望提供默认实现并允许子类覆盖它,则应该使用虚方法。选择哪种方法取决于你的具体需求,没有一种方法是最好的。抽象方法和虚方法有什么区别?在哪些情况下建议使用抽象或虚方法?哪种方法是最佳的?
抽象方法是没有实现的方法,必须在子类中实现,而虚方法有默认实现但可以被覆盖。如果希望强制子类实现特定方法,则应该使用抽象方法,如果希望提供默认实现并允许子类覆盖它,则应该使用虚方法。选择哪种方法取决于你的具体需求,没有一种方法是最好的。抽象函数不能有功能。你基本上是说,任何子类都必须提供自己的这个方法版本,但它太一般化了,甚至无法在父类中尝试实现。
虚函数,基本上是说,这里是可能或不可能足够好用于子类的功能。所以如果足够好用,就使用此方法,否则请覆盖我,并提供您自己的功能。
抽象函数没有具体实现,只能在抽象类中声明。这迫使派生类提供一个实现。
虚函数提供一个默认实现,可以存在于抽象类或非抽象类中。
例如:
public abstract class myBase
{
//If you derive from this class you must implement this method. notice we have no method body here either
public abstract void YouMustImplement();
//If you derive from this class you can change the behavior but are not required to
public virtual void YouCanOverride()
{
}
}
public class MyBase
{
//This will not compile because you cannot have an abstract method in a non-abstract class
public abstract void YouMustImplement();
}
virtual
或非virtual
。抽象成员(即抽象属性、抽象方法)就像虚拟方法一样,你可以覆盖它,只是它本身不带有默认实现。 - Mehrdad Afshari你必须始终覆盖抽象函数。
因此:
抽象函数:
虚函数:
解释:通过比喻来帮助你理解。
背景
我在一座21层的大楼里工作。我很担心火灾。世界上的某个地方总会有一场大火烧毁一座摩天大楼。但幸运的是,我们这里有一本关于火灾逃生指南:
FireEscape()
这基本上是一个名为FireEscape()的虚拟方法。
虚拟方法
对于99%的情况,这个计划非常好。这是一个简单有效的计划。但有1%的机会,即消防通道被堵塞或损坏,那么你就完了,除非你采取一些激进的行动,否则你将成为一块烤面包。使用虚拟方法,你可以做到这一点:你可以用自己的计划覆盖基本的FireEscape()计划:
换句话说,虚拟方法提供了一个基本计划,如果需要,可以进行覆盖。子类可以覆盖父类的虚拟方法,如果程序员认为适当的话。
抽象方法
并不是所有组织都很有条理。有些组织不进行消防演习。他们没有整体逃生政策。每个人都得自己想办法。管理层只关心这样的政策是否存在。
换句话说,每个人都被“强制”开发自己的FireEscape()方法。一个人会走出消防通道,另一个人会跳伞,另一个人会使用火箭推进技术从建筑物飞离,而另一个人则会绳降下去。管理层不关心你如何逃生,只要你有一个基本的FireEscape()计划 - 如果没有,那么组织将受到OHS的严厉打击。这就是抽象方法的含义。抽象方法: 当一个类包含一个抽象方法时,该类必须被声明为抽象类。 抽象方法没有具体的实现,因此从该抽象类派生出来的类必须提供实现这个抽象方法的具体代码。
虚方法: 一个类可以拥有一个虚方法。虚方法有一个实现。 当你继承了一个拥有虚方法的类后,你可以覆盖这个虚方法并提供额外的逻辑,或者用你自己的实现替换原有的逻辑。
何时使用什么:
在某些情况下,你知道某些类型应该拥有一个特定的方法,但是你不知道这个方法的具体实现方式。
在这种情况下,你可以创建一个接口,其中包含这个方法的签名。
然而,如果你有这样一种情况,但是你知道实现这个接口的类还会有另一个常用的方法(你已经可以提供其实现),你可以创建一个抽象类。
这个抽象类包含需要被重写的抽象方法和包含“常用”逻辑的另一个方法。
如果你有一个可以直接使用的类,但是想让继承者能够更改某些行为,尽管这不是强制要求,那么应该使用虚方法。
抽象方法是必须实现的方法,以创建一个具体类。声明在抽象类中(任何具有抽象方法的类都必须是抽象类),并且它必须在一个具体类中被实现。
虚拟方法是可以在派生类中使用覆盖关键字重写的方法,替换超类中的行为。如果您不进行重写,则会获得原始行为。如果您这样做,总是会获得新的行为。相对于不能被重写但可以隐藏原始方法的非虚拟方法,这是使用new
修饰符完成的。
请参考下面的示例:
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
当我实例化DerivedClass并调用SayHello或SayGoodbye时,我会得到“ Hi There”和“ See you later”。如果我调用HelloGoodbye,我会得到“ Hello”和“ See you later”。这是因为SayGoodbye是虚拟的,并且可以由派生类替换。SayHello只是被隐藏了,所以当我从我的基类调用它时,我得到原始的方法。抽象方法总是虚拟的,它们不能有实现。
这是主要区别。
基本上,如果您有其“默认”实现并希望允许后代更改其行为,则会使用虚拟方法。
使用抽象方法,您强制后代提供实现。
我通过对以下类(来自其他答案)进行了一些改进,从而使它更简单:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestOO
{
class Program
{
static void Main(string[] args)
{
BaseClass _base = new BaseClass();
Console.WriteLine("Calling virtual method directly");
_base.SayHello();
Console.WriteLine("Calling single method directly");
_base.SayGoodbye();
DerivedClass _derived = new DerivedClass();
Console.WriteLine("Calling new method from derived class");
_derived.SayHello();
Console.WriteLine("Calling overrided method from derived class");
_derived.SayGoodbye();
DerivedClass2 _derived2 = new DerivedClass2();
Console.WriteLine("Calling new method from derived2 class");
_derived2.SayHello();
Console.WriteLine("Calling overrided method from derived2 class");
_derived2.SayGoodbye();
Console.ReadLine();
}
}
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye\n");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public abstract class AbstractClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
//public virtual void SayGoodbye()
//{
// Console.WriteLine("Goodbye\n");
//}
public abstract void SayGoodbye();
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
public class DerivedClass2 : AbstractClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
// We should use the override keyword with abstract types
//public new void SayGoodbye()
//{
// Console.WriteLine("See you later2");
//}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
}