抽象函数和虚函数的区别是什么?在哪些情况下建议使用虚拟或抽象?哪一个是最好的方法?
抽象函数不能具有功能性。您基本上是说,任何子类都必须提供自己版本的这个方法,但是它太通用了,甚至不能在父类中实现。
一个虚函数,基本上是说,看,这里的功能对于子类来说可能不够好,也可能不够好。因此,如果它足够好,那么使用这个方法,如果不是,那么覆盖我,并提供您自己的功能。
抽象函数没有实现,只能在抽象类上声明。这将强制派生类提供实现。虚函数提供默认实现,它可以存在于抽象类或非抽象类中。举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } |
只有
您必须始终覆盖抽象函数。
因此:
抽象函数——当继承程序必须提供自己的实现时虚拟-当这是由继承人决定摘要函数:
它只能在抽象类中声明。它只包含方法声明而不是抽象类中的实现。它必须在派生类中重写。虚函数:
它既可以在抽象类中声明,也可以在非抽象类中声明。它包含方法实现。它可能被覆盖。抽象方法:当类包含抽象方法时,必须将该类声明为抽象。抽象方法没有实现,因此派生自该抽象类的类必须为该抽象方法提供实现。
虚拟方法:一个类可以有一个虚方法。虚拟方法有一个实现。当从具有虚拟方法的类继承时,可以覆盖虚拟方法并提供附加逻辑,或者用自己的实现替换逻辑。
何时使用什么:在某些情况下,您知道某些类型应该具有特定的方法,但是,您不知道该方法应该具有什么实现。在这种情况下,可以创建包含具有此签名的方法的接口。但是,如果您有这样的情况,但是您知道该接口的实现者也有另一个公共方法(您已经可以为其提供实现),那么您可以创建一个抽象类。然后这个抽象类包含抽象方法(必须覆盖)和另一个包含"公共"逻辑的方法。
如果您有一个类可以直接使用,但是您希望继承程序能够更改某些行为(尽管不是强制的),则应该使用虚拟方法。
解释:类比。希望它能帮助你。
上下文
我在一栋大楼的21层工作。我对火很偏执。世界上时不时地会有一场大火烧毁摩天大楼。但幸运的是,我们在这里的某个地方有一本说明书,告诉我们在发生火灾时该怎么做:
FireEscape ()
不收集物品步行到防火梯走出大楼这是一个名为FireEscape()的虚拟方法
虚方法
这个计划在99%的情况下都很好。这是一个行之有效的基本计划。但有1%的可能性,消防通道被堵塞或损坏,在这种情况下,你完全完蛋了,你会成为吐司,除非你采取一些激烈的行动。使用虚拟方法,您可以这样做:您可以用自己的计划版本覆盖基本的FireEscape()计划:
跑到窗口跳出窗外安全降落到底部换句话说,虚拟方法提供了一个基本的计划,如果需要,可以覆盖它。如果程序员认为合适,子类可以覆盖父类的虚方法。
抽象方法
并不是所有的组织都训练有素。有些组织不做消防演习。他们没有全面的逃跑政策。各人为己。管理层只对现有的这种策略感兴趣。
换句话说,每个人都必须开发自己的FireEscape()方法。一个人会从消防通道里走出来。另一个人会跳伞。另一个人将使用火箭推进技术飞离大楼。另一个人会掉下去。管理层并不关心你如何逃生,只要你有一个基本的防火逃生计划()——如果他们没有,你可以保证OHS会像砖头一样砸向组织。这就是抽象方法的含义。
这两者有什么区别?
抽象方法:子类被迫实现自己的FireEscape方法。使用虚拟方法,您有一个基本的计划等着您,但是如果它不够好,您可以选择实现自己的计划。
这并不难,对吧?
抽象方法是一种必须实现才能生成具体类的方法。声明在抽象类中(任何具有抽象方法的类都必须是抽象类),并且必须在具体类中实现。
虚方法是一个可以在派生类中使用重写(替换超类中的行为)重写的方法。如果不覆盖,就会得到原始行为。如果你这样做了,你总是会得到新的行为。这与不能重写但可以隐藏原始方法的非虚方法相反。这是使用
请看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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"); } } |
当我实例化
抽象方法是隐式虚方法。它们定义了必须呈现的行为,更像是接口所做的。
抽象方法总是虚拟的。它们不能有实现。
这是主要的区别。
基本上,如果您拥有虚方法的"默认"实现,并且希望允许后代更改其行为,那么您将使用虚方法。
使用抽象方法,您可以强制后代提供实现。
通过对以下类(来自其他答案)做一些改进,我使这个问题变得更简单了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 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 "); } public virtual void SayGoodbye() { Console.WriteLine("Goodbye "); } public void HelloGoodbye() { this.SayHello(); this.SayGoodbye(); } } public abstract class AbstractClass { public void SayHello() { Console.WriteLine("Hello "); } //public virtual void SayGoodbye() //{ // Console.WriteLine("Goodbye "); //} 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"); } } } |
绑定是将名称映射到代码单元的过程。
延迟绑定意味着我们使用名称,但延迟映射。换句话说,我们首先创建/提到这个名称,然后让一些后续流程处理代码到该名称的映射。
现在考虑:
与人类相比,机器确实擅长搜索和排序与机器相比,人类真的擅长发明和创新因此,简单的答案是:
换句话说,
"亲爱的运行时,做你最擅长的事情:搜索,把合适的代码绑定到这个名字上。"
而
"亲爱的程序员,请将适当的代码绑定到这个名称,做你最擅长的事情:发明"
为完整性考虑,重载意味着:
"亲爱的编译器,做你最擅长的事情:排序,把合适的代码绑定到这个名字上。"
当您希望继承程序扩展功能(如果它们愿意)时,您基本上使用虚拟方法。
当您希望继承者实现功能时,您使用抽象方法(在本例中,他们没有选择)
我在一些地方看到抽象方法定义如下。* *
"An Abstract Method must have to implement in the child class"
* *我觉得就像。
如果子类也是抽象的,则不必在子类中实现抽象方法。
抽象方法不能是私有方法。抽象方法不能在同一个抽象类中实现。
我会说…如果我们要实现抽象类,则必须重写基抽象类中的抽象方法。因为. .实现抽象方法是使用覆盖关键字。类似于虚方法。
没有必要在继承的类中实现虚方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ----------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(); } } |
虚拟方法:
虚拟意味着我们可以覆盖它。
虚函数有一个实现。当我们继承类时,我们可以覆盖虚拟函数并提供我们自己的逻辑。
方法实现时,可以更改虚函数的返回类型函数的子类(这可以说是一个概念跟踪)。抽象方法
抽象意味着我们必须覆盖它。
抽象函数没有实现,必须在抽象类中。
它只能被声明。这迫使派生类提供它的实现。
抽象成员是隐式虚的。在某些语言中,抽象可以称为纯虚。
1 2 3 4 5 6 7 8 9 | public abstract class BaseClass { protected abstract void xAbstractMethod(); public virtual void xVirtualMethod() { var x = 3 + 4; } } |
上面的大多数例子都使用代码——它们非常非常好。我不需要添加到他们所说的内容中,但是下面是一个简单的解释,它使用类比而不是代码/技术术语。
简单解释-使用类比解释
抽象方法
想想乔治?W?布什(George W Bush)。他对他的士兵说:"去伊拉克战斗吧。"就是这样。他所指定的是必须进行战斗。他没有具体说明具体将如何实现。但我的意思是,你不能只是出去"战斗":那到底是什么意思?我是用B-52还是derringer?那些具体的细节留给别人去处理。这是一个抽象方法。
虚方法
大卫·彼得雷乌斯在军队中地位很高。他定义了战斗的含义:
发现敌人中和他。饭后喝杯啤酒问题是这是一种非常普遍的方法。这是一个行之有效的好方法,但有时不够具体。对彼得雷乌斯来说,好消息是他的命令有回旋余地和范围——他允许其他人根据他们的特殊要求改变他对"战斗"的定义。
私人任务布洛格斯阅读彼得雷乌斯的命令,并根据他的特殊要求,被允许执行他自己版本的战斗:
发现敌人。朝他头部开一枪。回家有啤酒。马利基也从彼得雷乌斯那里接到同样的命令。他也要战斗。但他是个政客,不是步兵。很明显,他不能到处射杀他的政敌。因为彼得雷乌斯给了他一个虚拟的方法,马利基就可以根据自己的具体情况,实施自己版本的作战方法:
发现敌人。用捏造的罪名逮捕他。回家有啤酒。换句话说,虚拟方法提供了样板指令——但这些都是通用指令,可以根据具体情况,由军队的各个层级的人制定得更加具体。
两者之间的区别
乔治布什没有证明任何实施细节。这必须由其他人提供。这是一个抽象方法。
另一方面,彼得雷乌斯确实提供了实施细节,但他允许下属用自己的版本推翻他的命令,如果他们能想出更好的办法的话。
希望有帮助。
抽象函数(方法):
●抽象方法是用abstract关键字声明的方法。
●它没有身体。
●它应该由派生类实现。
●如果方法是抽象的,那么类应该是抽象的。
虚函数(方法):
●虚方法是用关键字virtual声明的方法,派生类方法可以使用override关键字重写虚方法。
●是否覆盖它取决于派生类。
抽象函数不能具有主体,必须由子类覆盖
虚函数将有一个主体,可能被子类覆盖,也可能不被子类覆盖
答案已经提供了很多次,但是关于何时使用它们的问题是设计时的决策。我认为将公共方法定义捆绑到不同的接口中,并将它们放到适当抽象级别的类中,这是一个很好的实践。当最好定义一个实现一组简洁接口的非抽象类时,将一组公共抽象和虚拟方法定义转储到类中会使类成为unistanable。与往常一样,这取决于什么最适合您的应用程序的特定需求。
在c#中没有调用虚类。
函数的
抽象函数只有签名,驱动类应该用功能覆盖。虚拟函数将包含驱动器类可能覆盖的部分功能,也可能不覆盖这部分功能你可以根据你的需要来决定。
从一般面向对象的角度来看:
关于抽象方法:当你在父类中放入一个抽象方法时,实际上你是在对子类说:嘿,注意你有一个这样的方法签名。如果你想使用它,你应该实现你自己的!
关于虚函数:当您在父类中放入虚方法时,您是在对派生类说:嘿,这里有一个功能可以为您做一些事情。如果这对你有用,就用它。如果没有,覆盖它并实现您的代码,甚至您可以在您的代码中使用我的实现!
这是关于这两个概念在OO中的不同的一些哲学
抽象方法没有实现。它在父类中声明。子类负责实现该方法。
虚方法应该在父类中有一个实现,它可以帮助子类选择是使用父类的实现,还是在子类中为该方法拥有一个新的实现。
抽象函数"只是"一个签名,没有实现。它在接口中用于声明如何使用该类。它必须在派生类中实现。
虚函数(实际上是方法)也是一个声明的函数,应该在继承层次结构类中实现。
该类的继承实例也继承实现,除非您在较低层次结构的类中实现它。
在这里,我正在编写一些示例代码,希望这是一个非常实际的示例,可以在非常基本的层次上查看接口、抽象类和普通类的行为。如果您想将此代码用作演示,还可以在github中找到它作为项目:https://github.com/usavas/JavaAbstractAndInterfaceDemo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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(){ // // } } } |
在c++背景下,c#虚函数对应c++虚函数,而c#抽象方法对应c++纯虚函数
抽象函数或方法是类公开的公共"操作名",其目标和抽象类一起,主要是在对象设计中针对对象必须实现的结构提供一种约束形式。
实际上,继承自其抽象类的类必须为该方法提供实现,通常编译器在不提供实现时就会引发错误。
使用抽象类和方法非常重要,主要是为了避免在设计类时关注实现细节,从而导致类结构与实现过于相关,从而在相互协作的类之间创建依赖关系和耦合。
虚函数或方法只是对类的公共行为建模的方法,但是我们可以在继承链中自由地修改它,因为我们认为子类可能需要为该行为实现一些特定的扩展。
它们都代表了面向对象范式中的一种多形性。
我们可以同时使用抽象方法和虚拟函数来支持一个好的继承模型。
我们为解决方案的主要对象设计了一个良好的抽象结构,然后通过定位那些更倾向于进一步专门化的对象来创建基本实现,并将这些实现作为虚拟实现,最后专门化我们的基本实现,最终"覆盖"继承的虚拟实现。
我的理解:
抽象方法:
只有抽象类才能包含抽象方法。派生类还需要实现该方法,该类中没有提供任何实现。
虚拟方法:
类可以声明它们,也可以提供它们的实现。派生类还需要实现方法来覆盖它。