抽象函数和虚函数有什么区别?
-
23-08-2019 - |
题
抽象函数和虚函数有什么区别?什么情况下建议使用virtual或abstract?哪一种是最好的方法?
解决方案
抽象函数不能具有的功能。你基本上说,所有子类必须给自己的这种方法的版本,但是它太普通,甚至尝试在父类中实现。
虚函数,基本上是说一下,这里有可能会或可能不会好足够的子类的功能。所以,如果它不够好,使用这种方法,如果没有,则覆盖了我,并提供自己的功能。
其他提示
这是抽象的功能没有FPGA实现,它只能在一个抽象类声明。这迫使派生类提供一个实现。
一个虚拟函数提供了一个默认实现,它可以在任一个抽象类或非抽象类存在。
因此,例如:
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
在某些语言中)。
您必须始终重写抽象函数。
因此:
- 抽象函数 - 什么时候 继承者必须提供自己的实现
- 虚拟的 - 什么时候 由继承人决定
抽象函数:
- 它只能在抽象类内部声明。
- 它仅包含方法声明不是抽象类中的实现。
- 必须在派生类中重写它。
虚拟功能:
- 它可以在抽象类和非抽象类中声明。
- 它包含方法实现。
- 它可能会被覆盖。
抽象方法: 当一个类包含一个抽象方法,这个类必须声明为抽象的。 抽象方法没有实现,因此,来自该抽象类派生的类,必须提供此抽象方法的实现。
虚拟方法: 一个类可以有一个虚拟方法。虚拟方法的实现。 当您从具有虚拟方法的类继承,你的可以的重写虚方法,并提供额外的逻辑,或者用自己的实现替换逻辑。
当使用什么: 在某些情况下,你知道,某些类型应该有一个具体的方法,但是,你不知道这个方法应该有什么样的实现。结果 在这种情况下,你可以创建一个包含与此签名的方法的接口。 但是,如果你有这样的情况,但你知道那个接口的实现也会有另一种常见的方法(您已经可以提供实现),你可以创建一个抽象类。 然后,该抽象类包含抽象方法(其必须被覆盖),并且其含有“共同”逻辑的另一种方法。
如果你有,可直接使用A类虚拟方法应使用,但对于要继承到能够改变某些行为,尽管它不是强制的。
解释:类比。希望它能帮助你。
语境
我在一栋大楼的 21 层工作。我对火很偏执。时不时地,在世界的某个地方,一场大火会烧毁一座摩天大楼。但幸运的是,我们这里有一份说明手册,介绍发生火灾时该怎么做:
火灾逃生()
- 请勿收集财物
- 步行至消防通道
- 走出大楼
这基本上是一个名为的虚拟方法 火灾逃生()
虚拟方法
这个计划对于 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
,我得到“你好”和“回头见”。如果我打电话HelloGoodbye
,我得到“你好”和“回头见”。这是因为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");
}
}
}
捆绑 是将名称映射到代码单元的过程。
后期绑定 意味着我们使用名称,但推迟映射。换句话说,我们首先创建/提及名称,然后让某些后续进程处理代码到该名称的映射。
现在考虑:
- 与人类相比,机器确实擅长搜索和排序
- 与机器相比,人类确实擅长发明和创新
所以,简短的答案是: virtual
是机器(运行时)的后期绑定指令,而 abstract
是人类(程序员)的后期绑定指令
换句话说, virtual
方法:
“亲爱的 运行, ,通过做你最擅长的事情将适当的代码绑定到这个名称: 寻找”
然而 abstract
方法:
“亲爱的 程序员, ,请通过您最擅长的方式将适当的代码绑定到该名称: 发明”
为了完整起见, 超载 方法:
“亲爱的 编译器, ,通过做你最擅长的事情将适当的代码绑定到这个名称: 排序”.
您基本上使用虚拟方法时,你要继承者来扩展功能,如果他们想。
您使用抽象方法,当你想继承者实现的功能(在这种情况下,他们别无选择)
我看到在一些地方的抽象方法被定义为如下。 **
“抽象方法必须在子类中实现”
** 我觉得它像。
这是没有必要的是一个抽象方法具有在子类中实现,如果子类也抽象强> ..
1)一种抽象方法的着强>是一个私有方法。 2)一个抽象方法的着强>在相同的抽象类来实现。
我想说..如果我们正在实施一个抽象类,您必须覆盖从基础抽象类的抽象方法。 因为..实施抽象方法是用替换强>键字。类似到虚拟方法。
<强>这是没有必要为在继承的类来实现的虚拟方法。强>
----------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();
}
}
虚拟方法:
虚拟意味着我们可以覆盖它。
虚函数有一个实现。当我们继承班级时,我们可以覆盖虚拟功能并提供自己的逻辑。
- 我们可以在实现时更改 Virtual 函数的返回类型
子类中的函数(可以说是一个概念
阴影)。
抽象方法
抽象意味着我们必须覆盖它。
抽象函数没有实现,必须位于抽象类中。
只能声明。这迫使派生类提供它的实现。
抽象成员是隐式虚拟的。在某些语言中,抽象可以称为纯虚拟。
public abstract class BaseClass { protected abstract void xAbstractMethod(); public virtual void xVirtualMethod() { var x = 3 + 4; } }
<强>抽象功能强>不能具有主体和必须由子类覆盖
<强>虚拟功能强>将有一个体和可以或可以不通过子类覆盖
上面的大多数示例都使用代码 - 而且它们非常非常好。我不需要补充他们所说的内容,但以下是使用类比而不是代码/技术术语的简单解释。
简单解释 - 使用类比解释
抽象方法
想想乔治·W·布什。他对他的士兵们说:“去伊拉克战斗吧”。就是这样。他所指定的只是必须进行战斗。他没有具体说明 如何 这正是将会发生的。但我的意思是,你不能只是出去“战斗”:这到底是什么意思?我该用 B-52 作战还是用我的德林格战机作战?这些具体细节留给其他人。这是一个抽象方法。
虚拟方法
大卫·彼得雷乌斯在军队中地位很高。他定义了战斗的含义:
- 找到敌人
- 中和他。
- 之后喝杯啤酒
问题是这是一个非常通用的方法。这是一个有效的好方法,但有时不够具体。对彼得雷乌斯来说,好处是他的命令有回旋余地和范围——他允许其他人根据他们的具体要求改变他对“战斗”的定义。
私人工作博客阅读了彼得雷乌斯的命令,并被允许根据他的特殊要求实施他自己的战斗版本:
- 寻找敌人。
- 朝他的头开枪。
- 回家
- 喝点啤酒吧
努里·马利基也收到了彼得雷乌斯的同样命令。他也要战斗。但他是一名政治家,而不是一名步兵。显然,他不能四处射击他的政敌。因为彼得雷乌斯给了他一个虚拟方法,所以马利基可以根据他的具体情况实现他自己版本的战斗方法:
- 寻找敌人。
- 用一些胡言乱语捏造的罪名逮捕他。
- 回家
- 喝点啤酒吧
换句话说,虚拟方法提供了样板指令 - 但这些是一般指令,可以由军队等级制度下的人们根据他们的具体情况制定更具体的指令。
两者的区别
乔治·布什没有证明任何实施细节。这必须由其他人提供。这是一个抽象方法。
另一方面,彼得雷乌斯 做 提供实施细节,但他已允许他的下属用他们自己的版本覆盖他的命令,如果他们能想出更好的东西的话。
希望有帮助。
摘要功能(方法):
●一个抽象方法是被声明与关键字抽象的方法。
●它没有身体。
●应该由派生类来实现。
●如果一个方法是抽象那么类应该抽象。
虚拟功能(方法):
●虚拟方法是被声明为方法关键字虚拟并且它可以通过使用override关键字的派生类的方法被覆盖。
●它是由派生类是否覆盖与否。
答案,已经提供了许多倍,但有关何时使用各自是设计时决定的问题。我认为这是很好的做法,试图捆绑常用的方法定义成不同的接口,并在适当的抽象级别它们拉入班。倾倒一套通用的抽象和虚拟方法定义成一个类呈现类unistantiable时它可能是最好的,以定义实现了一组简明的接口的非抽象类。与往常一样,这取决于什么最适合你的应用程序的特定需求。
从一般的面向对象视图: 点击 点击 关于抽象方法:当你把一个抽象的方法在父类实际上你说的到子类:嘿,注意,你有这样的方法签名。如果你想使用它,你应该实现自己的! 点击 点击 关于虚函数:当你把父类中的虚方法你说的派生类:嘿,这里有一个功能,为你做些什么。如果这是对你有用只是用它。如果没有,覆盖此并实现你的代码,甚至可以用我的实现在你的代码! 点击 点击 这是关于一些理念一般OO
这个两个概念之间的不同C# 中没有所谓的虚拟类。
对于功能
- 抽象函数只有签名,驱动类应该用功能重写。
- 虚拟功能将保留驱动器类可能会或可能不会根据要求覆盖它的部分功能
你可以根据你的要求来决定。
抽象方法不必须的是implementation.It在父类中定义。子类是resposible用于实施该方法。
虚拟方法应该在父类的实现,它有利于孩子上课做出的选择是否使用父类是实现或有本身为儿童类方法的新的实现。
这是抽象的功能是“仅仅”的签名,而无需实现。 它是在一个接口用于声明类可以如何使用。 它必须在派生类的一个来实现。
虚拟功能(方法实际上),是一个函数声明为好,并应在继承层次类之一实现。
这样类的继承实例中,继承执行,除非你实现它,在较低层级类。
从C ++背景,C#虚拟对应于C ++虚拟,而C#抽象方法对应于C ++纯虚函数
<强>抽象函数或方法强>是一个公共“的操作的名称”的一类,其宗旨,以抽象的类一起曝光,主要是提供约束的形式,对结构的对象的设计,一个目标必须实现。
事实上,从它的抽象类继承的类必须给这种方法的实现,通常编译器时,他们不引发错误。
使用抽象类和方法主要是重要,以避免通过设计类时着眼于实现细节,这些类结构太相关的实施方式中,因此,创建的类之间的依赖关系和耦合其中该协作。
虚函数或方法是一个简单的方法是模型类的公益行为,但我们可以把随意修改它继承链,因为我们认为子类可以有需要实现该行为的一些特定的扩展。
它们都代表的一种形式的 polymorpfhism 强>在面向对象的范式。
我们可以使用抽象方法和虚拟功能一起以支持良好的继承模型。
我们设计我们的解决方案中的主要画的好抽象的结构,然后通过定位那些更容易出现进一步专业化创建基本的实现,我们做这些的为虚函数,最后我们专注我们的基本实现,eventyually“超越”继承虚拟的
下面我写一些示例代码希望这可能是一个相当有形示例看到一个非常基本的水平的界面,抽象类和普通类的行为。 的https:// github上,如果你想使用它作为一个演示中,你也可以在github上此代码作为项目的.com / usavas / JavaAbstractAndInterfaceDemo
public interface ExampleInterface {
// public void MethodBodyInInterfaceNotPossible(){
// }
void MethodInInterface();
}
public abstract class AbstractClass {
public abstract void AbstractMethod();
// public abstract void AbstractMethodWithBodyNotPossible(){
//
// };
//Standard Method CAN be declared in AbstractClass
public void StandardMethod(){
System.out.println("Standard Method in AbstractClass (super) runs");
}
}
public class ConcreteClass
extends AbstractClass
implements ExampleInterface{
//Abstract Method HAS TO be IMPLEMENTED in child class. Implemented by ConcreteClass
@Override
public void AbstractMethod() {
System.out.println("AbstractMethod overridden runs");
}
//Standard Method CAN be OVERRIDDEN.
@Override
public void StandardMethod() {
super.StandardMethod();
System.out.println("StandardMethod overridden in ConcreteClass runs");
}
public void ConcreteMethod(){
System.out.println("Concrete method runs");
}
//A method in interface HAS TO be IMPLEMENTED in implementer class.
@Override
public void MethodInInterface() {
System.out.println("MethodInInterface Implemented by ConcreteClass runs");
// Cannot declare abstract method in a concrete class
// public abstract void AbstractMethodDeclarationInConcreteClassNotPossible(){
//
// }
}
}
要我的理解:
抽象方法:
只有抽象类可以容纳抽象方法。还派生类需要实现的方法和在类没有提供实现。
虚拟方法:
一个类可以声明这些,也提供相同的实施。还派生类需要实现的方法的覆盖它。