虚方法和抽象方法的区别

258

这里是来自MSDN的一些代码:

// compile with: /target:library 
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}

有人可以解释一下上面的代码,关于抽象方法和虚拟方法之间的区别吗?


你有具体的问题吗?你不明白什么? - Daniel Hilgarth
你从http://msdn.microsoft.com/en-us/library/ms173150(v=vs.80).aspx复制的所有内容。 - andy
@DanielHilgarth 更新了我的问题。请看一下。 - iJade
@Anandkumar 我只复制了抽象类和类成员的代码部分。你看一下。 - iJade
https://dev59.com/l3RC5IYBdhLWcg3wKtv2 - Y2theZ
覆盖Class-D的虚拟DoWork()方法是可选的,适用于它的所有直接子类/子类。上面的代码添加了一个中间抽象类E,强制对Class-E的所有子类重写Class-D的DoWork()方法-从根本上防止Class-E的所有子类使用Grandpa-Class-D的DoWork()。换句话说:隐藏了Class-D的DoWork()实现,这样Class-F就必须(以及它的所有兄弟类)各自形成自己的自定义实现DoWork() - MikeTeeVee
4个回答

608

虚方法有一个实现,并为派生类提供覆盖它的选项。抽象方法没有提供实现,强制派生类覆盖该方法。

因此,抽象方法中没有实际代码,并且(非抽象)子类必须覆盖该方法。虚方法可以有代码,通常是某些东西的默认实现,并且任何子类都可以使用override修饰符覆盖该方法并提供自定义实现。

public abstract class E
{
    public abstract void AbstractMethod(int i);

    public virtual void VirtualMethod(int i)
    {
        // Default implementation which can be overridden by subclasses.
    }
}

public class D : E
{
    public override void AbstractMethod(int i)
    {
        // You HAVE to override this method
    }
    public override void VirtualMethod(int i)
    {
        // You are allowed to override this method.
    }
}

12
说得非常好!不过有一个问题......在子类中,是否需要显式声明 override 来覆盖抽象方法 [因为要求它被重写]? - J.S. Orris
44
对于抽象方法,你必须明确声明它。对于虚方法,情况就更加复杂了。如果你没有在其中声明“override”关键字,原始方法将会被隐藏。如果这是你的目的,你可以使用“new”关键字来消除警告,但是想要隐藏方法的情况非常罕见。因此,除非你特别想使用方法隐藏,否则应始终使用“override”关键字。 - Dennisch
我们如何在 Class E 之外调用 Class E 的虚拟方法? - Jaydeep Shil
实际问题是:类D的虚方法能否成为抽象类E的抽象方法??并且,抽象类E的虚方法能在类F中被重写吗??可能吗?? - Vintage Coder
1
虚方法
  1. 虚方法有一个实现
  2. 可选重写(可以)
  3. 类不需要是虚拟的
  4. 虚方法可以在抽象和非抽象类中都存在。
抽象方法
  1. 必须被继承类覆盖(必须)
  2. 没有实现。
  3. 抽象方法必须在抽象类中
  4. 不能在没有继承的情况下实例化。
- Ahmed Zamil
显示剩余3条评论

96

首先你应该知道虚方法和抽象方法之间的区别。

抽象方法

  • 抽象方法存在于抽象类中,没有方法体。
  • 非抽象子类必须重写抽象方法。

虚方法

  • 虚方法可以存在于抽象及非抽象类。
  • 在派生类中不需要重写虚方法,但可以重写。
  • 虚方法必须有方法体......可以使用“override关键字”覆盖.....

6
抽象方法必须在非抽象子类中进行重写。但事实并非如此,您也可以在抽象类中进行重写。 - Shaminder Singh

17

抽象方法:

  • 如果在一个类中定义了抽象方法,则该类应声明为抽象类。

  • 抽象方法只应包含方法定义,不应包含方法体/实现。

  • 派生类必须重写抽象方法。

虚方法:

  • 虚方法可以被派生类重写,但不是强制性的。

  • 虚方法必须与定义一起具有方法体/实现。

示例:

public abstract class baseclass
        {
            public abstract decimal getarea(decimal Radius);

            public virtual decimal interestpermonth(decimal amount)
            {
                return amount*12/100;
            }

            public virtual decimal totalamount(decimal Amount,decimal principleAmount)
            {
                return Amount + principleAmount;
            }
        }

        public class derivedclass:baseclass
        {
            public override decimal getarea(decimal Radius)
            {
                return 2 * (22 / 7) * Radius;
            }

            public override decimal interestpermonth(decimal amount)
            {
                return amount * 14 / 100;
            }
        }

6

抽象方法必须在派生类中调用override,否则会产生编译时错误。

而对于虚方法,你可以选择是否覆盖它,这取决于它是否足够好用。

例子:

abstract class twodshape
{
    public abstract void area(); // no body in base class
}

class twodshape2 : twodshape
{
    public virtual double area()
    {
        Console.WriteLine("AREA() may be or may not be override");
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接