抽象函数不能具有功能。您基本上是在说,任何子类都必须提供自己的该方法的版本,但是它太笼统了,甚至无法尝试在父类中实现。
虚函数基本上是在说看,这里的功能对于子类来说可能足够好,也可能不够好。因此,如果足够好,请使用此方法;否则,请覆盖我并提供您自己的功能。
抽象函数没有实现,只能在抽象类上声明。这迫使派生类提供实现。
虚函数提供了默认实现,它可以存在于抽象类或非抽象类上。
因此,例如:
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();
}
abstract
类可以具有abstract
成员。 abstract
类继承的非abstract
类必须 override
其abstract
成员。 abstract
成员是隐式virtual
。 abstract
成员不能提供任何实现( abstract
在某些语言中称为pure virtual
)。 您必须始终重写抽象函数。
从而:
抽象功能:
虚函数:
抽象方法:当类包含抽象方法时,必须将该类声明为抽象方法。抽象方法没有实现,因此,从该抽象类派生的类必须为该抽象方法提供一个实现。
虚方法:类可以具有虚方法。虚拟方法有一个实现。当您从具有虚拟方法的类继承时, 可以覆盖该虚拟方法并提供其他逻辑,或者将逻辑替换为自己的实现。
何时使用什么:在某些情况下,您知道某些类型应具有特定的方法,但是您不知道此方法应具有的实现。
在这种情况下,您可以创建一个包含带有此签名的方法的接口。但是,如果遇到这种情况,但是您知道该接口的实现者还将有另一个通用方法(您已经可以为其提供实现),则可以创建一个抽象类。然后,该抽象类包含抽象方法(必须重写)和另一个包含 “公共” 逻辑的方法。
如果您有一个可以直接使用的类,但是您希望继承者能够更改某些行为,尽管不是强制性的,则应使用虚拟方法。
说明:类推。希望它将对您有所帮助。
语境
我在建筑物的 21 楼工作。我对火灾抱有偏执。时不时地,在世界某个地方,大火烧毁了刮板。但幸运的是,在这里,我们有一份说明手册,介绍发生火灾时的处理方法:
火灾逃生()
这基本上是一个称为FireEscape()的虚拟方法
虚方法
该计划在 99%的情况下都非常好。这是可行的基本计划。但是,只有 1%的可能性防火通道会被阻塞或损坏,在这种情况下,您将完全被拧紧,除非采取严厉措施,否则您将变成烤面包。使用虚方法,您可以做到这一点:您可以使用自己的计划版本覆盖基本的 FireEscape()计划:
换句话说, 虚拟方法提供了一个基本计划,如果需要,可以将其覆盖 。如果程序员认为合适,子类可以覆盖父类的虚拟方法。
抽象方法
并非所有组织都进行了深入的研究。一些组织不进行消防演习。他们没有整体的逃生政策。每个人都是他自己。管理层仅对现有这样的政策感兴趣。
换句话说,每个人被迫发展自己的 FireEscape()方法。一个人会走出防火梯。另一个家伙会降落伞。另一个家伙将使用火箭推进技术从建筑物上飞走。另一个家伙会逃走。只要您有基本的 FireEscape()计划,管理人员就不会在意您如何逃生 - 如果没有,您可以保证 OHS 会像一吨砖一样落在组织上。这就是抽象方法的含义。
两者又有什么区别?
抽象方法:子类被强制实现自己的 FireEscape 方法。使用虚拟方法时,您有一个基本计划正在等待您,但是如果还不够好的话,可以选择实施自己的计划。
现在不是那么难吗?
抽象方法是必须实现以构成具体类的方法。声明在抽象类中(任何具有抽象方法的类都必须是抽象类),并且必须在具体类中实现。
虚方法是一种可以使用覆盖在派生类中覆盖, 替换超类中行为的方法。如果不覆盖,则会得到原始行为。如果这样做,您总是会得到新的行为。这与非虚拟方法相反,后者不能被覆盖但可以隐藏原始方法。这是使用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” 和 “稍后见”。如果我致电HelloGoodbye
, HelloGoodbye
收到 “Hello” 和 “稍后见”。这是因为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");
}
}
}