题 抽象函数和虚函数有什么区别?


抽象函数和虚函数有什么区别?在哪些情况下建议使用虚拟或抽象?哪种方法更正确?


1304
2017-12-24 14:11


起源


必须覆盖抽象函数,同时可以覆盖虚函数。 - Jordan Parmer
虚函数可以在基类中具有默认/通用实现。 - Martin
这里的关键词是 抽象;它们不存在,只是对函数是什么的模糊概念(方法签名) - Cole Johnson


答案:


抽象函数不具备功能。 你基本上是在说,任何一个子类必须给出他们自己的这个方法的版本,但是它太普遍甚至不能尝试在父类中实现。

虚拟功能,基本上是说看,这里的功能对于孩子班级来说可能是也可能不够好。因此,如果它足够好,请使用此方法,如果没有,则覆盖我,并提供您自己的功能。


2325
2017-12-24 14:14



当然,如果你覆盖一个虚方法,你总是可以通过调用base.Foo(...)来引用父方法。 - Brann
谢谢。与MSDN文档中的任何内容相比,这是一个更好,更简单的解释。(我读了五分钟后感到头痛: msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx) - Jake
来自Java,我有点困惑为什么我们需要将它变为虚拟,直到我读到这个: stackoverflow.com/a/1062126/193634 - Rosdi Kasim
@MeqDotNet这意味着如果你喜欢我的实现,请使用我,如果不比我自己写得更好:) - Usman Y
这应该在Microsoft参考库中,我花了10分钟阅读并仍然感到困惑。 - SamChen


抽象函数没有实现,只能在抽象类上声明。这会强制派生类提供实现。虚函数提供默认实现,它可以存在于抽象类或非抽象类中。例如:

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();
}

244
2017-12-24 14:19



查看示例代码非常有用 - 有助于使答案中的各种解释更加清晰。 - Simon Tewsi
我回滚了以前版本的答案:这两个类只是示例,第一个类将编译,因为它标记为抽象,第二个不会。 MyBase是否从其他类继承是无关紧要的。 - Dirk
不是你的 MyBase 班级必须实施 抽象 上课,不知何故?我不经常这样做,所以我可能会弄错。我在你的例子中没有看到。 - jp2code
在上面的例子中,MyBase显示了你不能做的事情。也就是说,你不能在非抽象类中使用抽象方法 - JoshBerke


  1. 只要 abstract 课可以有 abstract 成员。
  2. abstract 从一个继承的类 abstract 类 必须  override 它的 abstract 成员。
  3. 一个 abstract 成员是含蓄的 virtual
  4. 一个 abstract 会员不能提供任何实施(abstract 叫做 pure virtual 在某些语言中)。

68
2018-04-16 09:03



3号对我来说没有意义。我想你的意思是说“抽象类的成员是隐式虚拟的”(即,你可以为它提供功能,而不必指定它是虚拟的)。 - Hobo Spider
不,我的意思正是我写的。抽象类的成员可以是 virtual 或非virtual。一个 abstract member(即抽象属性,抽象方法)就像一个虚方法,即你可以覆盖它,除了它不带有默认实现。 - Mehrdad Afshari
引用“抽象成员”是隐含的“虚拟”。但我在某个地方看到,有人通过明确地添加“虚拟”关键字来创建抽象成员。这是没有必要的,事实上它给了我一个疑问,直到我读到你的答案。 - bonCodigo
请包括第4点的支持参考。并且您的帖子不会带来以前没有的任何其他内容。 - Rafael


您必须始终覆盖抽象函数。

从而:

  • 抽象功能 - 什么时候 继承者必须提供自己的实现
  • 虚拟 - 什么时候 这取决于继承人的决定

49
2017-12-24 14:13





摘要功能:

  1. 它只能在抽象类中声明。
  2. 它只包含 方法声明不是抽象类中的实现。
  3. 必须在派生类中重写它。

虚函数:

  1. 它可以在abstract和non abstract类中声明。
  2. 它包含方法实现。
  3. 它可能被覆盖了。

30
2018-05-28 07:52





抽象方法: 当类包含抽象方法时,该类必须声明为抽象。 抽象方法没有实现,因此,从该抽象类派生的类必须为此抽象方法提供实现。

虚拟方法: 一个类可以有一个虚方法。虚方法有一个实现。 当您从具有虚方法的类继承时,您 能够 覆盖虚方法并提供其他逻辑,或用您自己的实现替换逻辑。

什么时候用什么: 在某些情况下,您知道某些类型应该具有特定方法,但是,您不知道此方法应该具有哪种实现。
在这种情况下,您可以创建一个包含具有此签名的方法的接口。 但是,如果您有这种情况,但是您知道该接口的实现者还将有另一个常用方法(您已经可以为其提供实现),则可以创建一个抽象类。 然后,这个抽象类包含抽象方法(必须重写),以及另一个包含'common'逻辑的方法。

如果您有一个可以直接使用的类,但是您希望继承者能够更改某些行为,但是它不是必需的,则应该使用虚方法。


27
2018-04-16 09:03





解释:有类比。希望它会对你有所帮助。

上下文

我在一栋建筑的21楼工作。我对火很偏执。在世界的某个地方,每时每刻都有一场大火烧毁了天空刮板。但幸运的是,我们在这里有一个说明手册,以防发生火灾时该做什么:

火灾逃生()

  1. 不要收集物品
  2. 走到火灾逃生
  3. 走出建筑物

这基本上是一个名为的虚拟方法 火灾逃生()

虚方法

对于99%的情况,这个计划非常好。这是一个有效的基本计划。但是火灾逃生被阻挡或损坏的可能性为1%,在这种情况下,你完全被拧紧,除非你采取一些激烈的行动,否则你会变成烤面包。使用虚拟方法,您可以这样做:您可以使用您自己的计划版本覆盖基本的FireEscape()计划:

  1. 运行到窗口
  2. 跳出窗外
  3. 降落伞安全到底

换一种说法 虚方法提供了一个基本计划,如果需要,可以覆盖。如果程序员认为合适,子类可以覆盖父类的虚方法。

抽象方法

并非所有组织都经过精心培训。有些组织不进行消防演习。他们没有全面的逃避政策。每个人都是为了自己。管理层只对现有的此类政策感兴趣。

换句话说,每个人都是 被迫 开发自己的FireEscape()方法。一个人会走出火灾逃生。另一个人会降落伞。另一个人将使用火箭推进技术飞离建筑物。另一个人会下降。管理层不在乎 怎么样 你逃脱了,只要你有一个基本的FireEscape()计划 - 如果你没有,你可以保证OHS会像一吨砖一样落在组织上。这就是抽象方法的含义。

两者又有什么区别?

抽象方法:子类是 被迫 实现自己的FireEscape方法。使用虚拟方法,您有一个等待您的基本计划,但可以选择 实现自己的 如果不够好的话。

现在那不是那么难吗?


23
2018-06-16 01:01





抽象方法是必须实现以创建具体类的方法。声明在抽象类中(并且任何具有抽象方法的类必须是抽象类)并且必须在具体类中实现。

虚方法是一种可以使用覆盖在派生类中重写的方法, 更换 超类中的行为。如果不覆盖,则会获得原始行为。如果你这样做,你总会得到新的行为。这与非虚拟方法相反,它不能被覆盖,但可以隐藏原始方法。这是使用 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,我得到“你好”和“以后见”。如果我打电话 HelloGoodbye,我得到“你好”和“以后见”。这是因为 SayGoodbye 是虚拟的,可以用派生类替换。 SayHello 只是隐藏,所以当我从我的基类调用它时,我得到了我原来的方法。

抽象方法是隐式虚拟的。它们定义必须存在的行为,更像界面。


21
2018-04-16 09:13





抽象方法总是虚拟的。他们无法实施。

这是主要的区别。

基本上,如果您具有虚拟方法,并且希望允许后代更改其行为,则可以使用虚方法。

使用抽象方法,可以强制后代提供实现。


9
2018-04-16 09:00