我想知道两个约定之间的区别:
有什么区别?
答案 0 :(得分:9)
与接口非常相似,抽象类旨在表达您的类型的一组已知操作。但是,与接口不同,抽象类允许您实现可由任何派生类型使用的公共/共享功能。 E.g:
public abstract class LoggerBase
{
public abstract void Write(object item);
protected virtual object FormatObject(object item)
{
return item;
}
}
在上面这个非常基本的例子中,我基本上做了两件事:
鉴于我知道LoggerBase
的任何派生类型都有Write
方法,我可以称之为。以上作为接口的等价物可以是:
public interface ILogger
{
void Write(object item);
}
作为一个抽象类,我可以提供一个额外的服务FormatObject
,可以选择覆盖,比如说我写ConsoleLogger
,例如:
public class ConsoleLogger : LoggerBase
{
public override void Write(object item)
{
Console.WriteLine(FormatObject(item));
}
}
通过将FormatObject
方法标记为虚拟,这意味着我可以提供共享实现。我也可以覆盖它:
public class ConsoleLogger : LoggerBase
{
public override void Write(object item)
{
Console.WriteLine(FormatObject(item));
}
protected override object FormatObject(object item)
{
return item.ToString().ToUpper();
}
}
所以,关键部分是:
abstract
类必须继承。abstract
方法必须在派生类型中实现。virtual
方法可以在派生类型中覆盖。在第二种情况下,因为您不会将功能添加到抽象基类,所以在直接处理基类的实例时无法调用该方法。例如,如果我实施ConsoleLogger.WriteSomethingElse
,我就无法从LoggerBase.WriteSomethingElse
调用它。
答案 1 :(得分:4)
将抽象方法放在基类中然后在子类中实现它们的想法是,您可以使用父类型而不是任何特定的子类。例如,假设您要对数组进行排序。您可以将基类定义为类似
的类abstract class Sorter {
public abstract Array sort(Array arr);
}
然后,您可以在子类中实现各种算法,例如quicksort,mergesort,heapsort。
class QuickSorter {
public Array sort(Array arr) { ... }
}
class MergeSorter {
public Array sort(Array arr) { ... }
}
您可以通过选择算法
来创建排序对象Sorter sorter = QuickSorter();
现在你可以通过sorter
,而不会暴露这样一个事实,即它是一个快速排序。要对数组进行排序
Array sortedArray = sorter.sort(someArray);
通过这种方式,实现的细节(您使用的算法)与对象的接口分离(事实上它对数组进行排序)。
一个具体的优点是,如果在某些时候您需要不同的排序算法,那么您可以在此单行中将QuickSort()
更改为MergeSort
,而无需在其他任何位置更改它。如果您在父级中未包含sort()
方法,则每次调用QuickSorter
时都必须向下转换为sort()
,然后更改算法将更加困难。
答案 2 :(得分:2)
在案例1)中,您可以从抽象基类型访问这些方法,而无需知道确切的类型(抽象方法是虚方法)。
抽象类的要点通常是在基类上定义一些契约,然后由派生类实现(在这种情况下,重要的是要认识到接口是一种“纯抽象类”)。 / p>
答案 3 :(得分:0)
换句话说,使用基类中的抽象方法,您可以在基类中调用该抽象方法的其他方法中编写代码。
显然,如果基类没有那些方法......你就不能称之为......
答案 4 :(得分:0)
抽象函数不具备任何功能。你基本上是在说,任何一个子类必须给出他们自己的这个方法的版本,但是它太普遍甚至不能尝试在父类中实现。一个虚函数,基本上就是说看,这里的功能对于子类来说可能是也可能不够好。所以,如果它足够好,请使用此方法,如果没有,则覆盖我,并提供您自己的功能......
当然,如果你覆盖虚方法,你总是可以通过调用base.myVirtualMethod()
来引用父方法
答案 5 :(得分:-1)
好的,当你看到这样的方法时:
A.Foo();
你真正拥有的(幕后)是这样的签名。
Foo(A x);
当你致电A.Foo()
时,你真的在呼叫Foo(this)
,其中this
是对A类型对象的引用。
现在,有时候您希望Foo(A|B|C|D...)
Foo
是一种方法,可以 类型A,或B,或C或D.但是你不想担心你传递的是什么类型,你只是希望它根据传入的类型做一些不同的事情。抽象方法让你这样做,这是他们唯一的目的。