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

在哪种情况下,build议使用虚拟还是抽象? 哪一种更正确?

抽象函数不能有function。 你基本上是说,任何一个子类都必须自己给出这个方法的版本,但是它太笼统了,甚至不能尝试在父类中实现。

一个虚拟函数 ,基本上是说看,这里的function,可能会或可能不足够的孩子类。 所以,如果它足够好,使用这种方法,如果没有,然后覆盖我,并提供自己的function。

抽象函数没有实现,只能在抽象类上声明。 这迫使派生类提供一个实现。 虚函数提供了一个默认实现,它可以存在于抽象类或非抽象类中。 举个例子:

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(); } 
  1. 只有abstract类可以有abstract成员。
  2. abstract类inheritance的非abstract必须 overrideabstract成员。
  3. abstract成员是隐式virtual
  4. abstract成员不能提供任何实现( abstract在某些语言中被称为pure virtual )。

您必须始终重写一个抽象函数。

从而:

  • 抽象函数 – 当inheritance者必须提供自己的实现
  • 虚拟 – 何时由inheritance人决定

摘要function:

  1. 它只能在抽象类中声明。
  2. 它只包含方法声明而不包含在抽象类中的实现。
  3. 它必须在派生类中被覆盖。

虚拟function:

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

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

虚拟方法:一个类可以有一个虚拟的方法。 虚拟方法有一个实现。 从具有虚拟方法的类inheritance时, 可以重写虚方法并提供其他逻辑,也可以将逻辑replace为您自己的实现。

什么时候使用什么:在某些情况下,你知道某些types应该有一个特定的方法,但是,你不知道这个方法应该有什么实现。
在这种情况下,您可以创build一个包含具有此签名的方法的接口。 但是,如果你有这样的情况,但是你知道那个接口的实现者也会有另一个通用的方法(你可以提供这个方法),你可以创build一个抽象类。 这个抽象类包含抽象方法(必须被重写)和另一个包含“通用”逻辑的方法。

如果你有一个可以直接使用的类,但是你希望inheritance者能够改变某些行为,尽pipe它不是强制性的,那么应该使用虚拟方法。

抽象方法是一个必须实现的方法来创build一个具体的类。 声明在抽象类中(任何具有抽象方法的类都必须是抽象类),并且必须在具体类中实现。

虚拟方法是一种可以在派生类中使用覆盖重写的方法, replace超类中的行为。 如果你不覆盖,你会得到原来的行为。 如果你这样做,你总是会得到新的行为。 这种反对不是虚拟方法,即不能被覆盖,但可以隐藏原来的方法。 这是使用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并调用SayHelloSayGoodbye ,我会得到“Hi There”和“稍后再见”。 如果我打电话给HelloGoodbye ,我会收到“Hello”和“稍后再见”。 这是因为SayGoodbye是虚拟的,可以被派生类replace。 SayHello只是隐藏的,所以当我从我的基类调用,我得到我原来的方法。

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

解释:用类比。 希望它会帮助你。

上下文

我在一幢大厦的二十一楼工作。 而且我对火灾有偏见。 在世界的某个地方,一场又一次的火灾正在燃烧着天空的刮板。 但幸运的是,我们在这里有一个指导手册,说明如何处理火灾:

火灾逃生()

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

这基本上是一个名为FireEscape()的虚拟方法,

虚拟方法

这个计划在99%的情况下是相当不错的。 这是一个可行的基本计划。 但是有1%的机会让火灾逃生被堵塞或者损坏,在这种情况下,你完全被搞砸了,除非你采取一些激烈的行动,否则你会变成烤面包。 使用虚拟方法,您可以做到这一点:您可以用您自己的计划版本覆盖基本的FireEscape()计划:

  1. 运行到窗口
  2. 跳出窗口
  3. 降落伞安全地到了最后

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

抽象的方法

并不是所有的组织都钻好。 有些组织不做消防演习。 他们没有全面的逃生政策。 每个人都是为了自己。 pipe理层只对这样的政策感兴趣。

换句话说,每个人都被迫开发自己的FireEscape()方法。 一个人会走出逃生。 另一个人会降落伞。 另一个人将使用火箭推进技术飞离build筑物。 另一个人会跳出来。 pipe理层并不关心你如何逃脱,只要你有一个基本的FireEscape()计划 – 如果他们不这样做,你可以保证职业安全与健康将像组织一样,在一吨砖头下降。 这就是抽象方法的含义。

两者又有什么区别?

抽象方法:子类被迫实现自己的FireEscape方法。 用虚拟方法,你有一个基本的计划在等着你,但是如果它不够好,可以select实现你自己的计划。

那现在不是那么难吗?

抽象方法总是虚拟的。 他们不能有一个实现。

这是主要的区别。

基本上,如果你有'默认'的实现,并且希望允许后代改变它的行为,你将使用一个虚拟的方法。

用抽象的方法,你强迫后代提供一个实现。

我通过对以下类进行了一些改进(来自其他答案),使其更简单:

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

如果希望inheritance者扩展function,则基本上使用虚拟方法。

当你希望inheritance者实现这个function时,你可以使用抽象方法(在这种情况下,他们没有select)

我在一些地方看到抽象方法定义如下。 **

“抽象方法必须在子类中实现”

**我觉得这是。

如果子类也是抽象的那么抽象方法不必在子类中实现。

1)抽象方法不能成为一个私有方法。 2)抽象方法不能在同一个抽象类中实现。

我会说..如果我们正在实现一个抽象类,你必须重写基抽象类的抽象方法。 因为实现抽象方法是用覆盖关键字。类似于虚拟方法。

虚拟方法不需要在inheritance类中实现。

  ----------CODE-------------- public abstract class BaseClass { public int MyProperty { get; set; } protected abstract void MyAbstractMethod(); public virtual void MyVirtualMethod() { var x = 3 + 4; } } public abstract class myClassA : BaseClass { public int MyProperty { get; set; } //not necessary to implement an abstract method if the child class is also abstract. protected override void MyAbstractMethod() { throw new NotImplementedException(); } } public class myClassB : BaseClass { public int MyProperty { get; set; } //You must have to implement the abstract method since this class is not an abstract class. protected override void MyAbstractMethod() { throw new NotImplementedException(); } } 

抽象函数不能有一个主体,必须被子类重载

虚函数将有一个正文,可能会或可能不会被子类覆盖

上面的例子大多使用代码 – 它们非常好。 我不需要添加他们所说的内容,但是下面是一个简单的解释,它使用类比而不是代码/技术术语。

简单的解释 – 使用类比的解释

抽象方法

想想乔治·W·布什。 他对士兵说:“去伊拉克战斗”。 就是这样。 他所指定的只是战斗必须完成。 他没有具体说明会发生什么。 但是我的意思是,你不能只是出去“打架”:那究竟是什么意思? 我和B-52还是我的呃呃打架? 这些具体细节留给其他人。 这是一个抽象的方法。

虚拟方法

大卫·彼得雷乌斯(David Petraeus)是军队中最高的。 他已经定义了什么样的斗争手段

  1. find敌人
  2. 中和他。
  3. 之后喝一杯啤酒

问题是这是一个非常普遍的方法。 这是一个很好的方法,但有时不够具体。 彼得雷乌斯的好处是,他的命令有余地和范围 – 他允许别人根据他们的特殊要求改变他的“战斗”的定义。

私人工作Bloggs读取彼得雷乌斯的命令,并根据他的特殊要求被允许实施他自己的战斗版本:

  1. find敌人。
  2. 把他射在脑袋里。
  3. 回家
  4. 喝啤酒

Nouri al Maliki也收到了Petraeus的同样命令。 他也是要打。 但他是一个政治家,而不是一个步兵的人。 显然,他不能四处射杀他的政治家的敌人。 因为彼得雷乌斯已经给了他一个虚拟的方法,所以马利基可以根据自己的具体情况实施他自己的战斗方式:

  1. find敌人。
  2. 让他以一些BS被控的罪名逮捕他。
  3. 回家
  4. 喝啤酒

换句话说,一个虚拟的方法提供了样板的指示 – 但是这些是一般的指示,根据他们的具体情况,这些指示可以由军人的军事指令来更加具体化。

两者的区别

  • 乔治·布什没有certificate任何实施细节。 这必须由其他人提供。 这是一个抽象的方法。

  • 另一方面彼得雷乌斯确实提供了实施细节,但是他允许下属用他们自己的版本来覆盖他的订单,只要他们能够提出更好的build议。

希望有所帮助。

抽象函数(方法):

●抽象方法是一种用关键字abstract声明的方法。

●没有身体。

●应该由派生类来实现。

●如果一个方法是抽象的,那么这个类应该抽象。

虚函数(方法):

●虚拟方法是使用关键字virtual声明的方法,可以使用override关键字通过派生类方法重写。

●它的派生类天气是否覆盖它。

绑定是将名称映射到一段代码的过程。

后期绑定意味着我们使用该名称,但延迟映射。 换句话说,我们首先创build/提及名称,并让后续进程处理代码到该名称的映射。

现在考虑:

  • 与人类相比,机器真的很擅长search和分类
  • 与机器相比,人类善于创造和完善

所以,简短的回答是: virtual是机器(运行时)的后期绑定指令,而abstract是人类(程序员)的后期绑定指令,

换句话说, virtual手段:

“亲爱的运行时 ,通过做你最擅长的事情来把适当的代码绑定到这个名字上: search

abstract手段:

“亲爱的程序员 ,请通过做你最擅长的事情来把适当的代码绑定到这个名字上: 创build

为了完整起见, 超载意味着:

“亲爱的编译器 ,通过做你最擅长的事情来把适当的代码绑定到这个名字上: search (和sorting )”。

答案已经提供了很多次,但关于什么时候使用的问题是一个devise时间的决定。 我认为这是一个很好的习惯,试图将常见的方法定义捆绑到不同的接口中,并将它们拉入适当抽象层次的类中。 将一组通用的抽象方法和虚拟方法定义转储到类中,可以最好地定义一个实现一组简洁接口的非抽象类。 一如既往,这取决于什么最适合您的应用程序的特定需求。

在C#中没有什么叫虚拟类。

对于function

1.抽象函数只有签名,驱动类应该覆盖function。 2.虚拟function将保留驱动类的function部分可以或不可以根据需要来覆盖它

你可以根据你的需求来决定

从一般对象的angular度来看:

关于抽象方法 :当你在父类中放置一个抽象方法时,实际上你正在对子类进行说明:嗨,注意你有一个像这样的方法签名。 如果你想使用它,你应该实现自己的!

关于虚函数 :当你在父类中放置一个虚拟方法时,你正在对派生类进行说明:嘿,这里有一个function可以为你做些事情。 如果这对你使用它是有用的。 如果没有,重写这个并实现你的代码,即使你可以在你的代码中使用我的实现!

这是一般OO中这两个概念之间不同的哲学

以我的理解:

摘要方法:

只有抽象类可以抽象的方法。 此外,派生类需要实现该方法,并且没有在类中提供实现。

虚拟方法:

一个类可以声明这些,也提供相同的实现。 派生类也需要实现该方法来覆盖它。