抽象方法和虚拟方法有什么区别?在哪些情况下,建议使用抽象方法或虚拟方法?哪一种是最好的方法?


当前回答

抽象函数没有实现,只能在抽象类上声明。这迫使派生类提供实现。

虚拟函数提供默认实现,它可以存在于抽象类或非抽象类上。

例如:

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

其他回答

绑定是将名称映射到代码单元的过程。

后期绑定意味着我们使用名称,但延迟映射。换言之,我们首先创建/提及名称,然后让后续流程处理代码到该名称的映射。

现在考虑:

与人类相比,机器确实擅长搜索和排序与机器相比,人类确实擅长发明和创新

因此,简单的答案是:virtual是机器(运行时)的后期绑定指令,而abstract是人类(程序员)的后期约束指令

换句话说,虚拟意味着:

亲爱的运行时,通过执行您最擅长的操作将适当的代码绑定到此名称:搜索

抽象意味着:

亲爱的程序员,请尽你所能将适当的代码绑定到这个名字上:发明

为完整起见,重载意味着:

“亲爱的编译器,通过做你最擅长的事情,将适当的代码绑定到这个名称:排序”。

当您希望继承者根据需要扩展功能时,基本上可以使用虚拟方法。

当您希望继承者实现功能时,可以使用抽象方法(在这种情况下,他们别无选择)

我通过对以下课程(从其他答案)进行一些改进,使这一点更简单:

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/real(final)方法:该方法可以被重写/不能被重写。

特别是,抽象方法是虚拟的,而真实方法是具体的。

抽象函数:

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

虚拟功能:

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