关于抽象类的讨论

来源:互联网 发布:淘宝网宝贝链接打不开 编辑:程序博客网 时间:2024/04/30 18:27

http://blog.csdn.net/qltouming/archive/2007/04/11/1561124.aspx

一。何时使用抽象类

当需要一组相关组件来包含一组具有相同功能的方法,但同时要求在其他方法实现中具有灵活性时,可以使用抽象类。当预料可能出现版本问题时,抽象类也具有价值,因为基类比较灵活并易于被修改。有关详细信息,请参见抽象类与接口建议。

抽象类与接口建议请参见
抽象类 | 组件中的多态性 | MustInherit (Visual Basic) | abstract (C#)
选 择将功能设计为接口还是抽象类(在 Visual Basic 中为 MustInherit 类)有时是一件困难的事。“抽象类”是一种不能实例化而必须从中继承的类。抽象类可以完全实现,但更常见的是部分实现或者根本不实现,从而封装继承类的通 用功能。有关详细信息,请参见抽象类。

相反,“接口”是完全抽象的成员集合,可以被看作是为操作定义合同。接口的实现完全留给开发者去做。

接口和抽象类对组件交互都很有用。如果一个方法要求一个参数形式的接口,则任何实现该接口的对象都可以用在该参数中。例如:

' Visual Basic
Public Sub Spin (ByVal widget As IWidget)
End Sub
// C#
public void Spin (IWidget widget)
{}
此方法可以接受任何将 IWidget 实现为小部件参数的对象,即使 IWidget 的实现可能相差很大。抽象类也允许这种多态性,但须注意以下几点:

类可能只是从一个基类继承,所以如果要使用抽象类为一组类提供多态性,这些类必须都是从那个类继承的。
抽象类还可能提供已实现的成员。因此,可以用抽象类确保特定数量的相同功能,但不能用接口这样做。
这里是一些建议,帮助您决定使用接口还是抽象类为组件提供多态性。

如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。
如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。
------------------------------------------------------------------------------------------
二。网友的疑问

using System;
abstract public class Window
{
protected int top;
protected int left;
public Window(int top1,int left1)
{
this.top = top1;
this.left = left1;
}
abstract public void DrawWindow();
}

public class ListBox:Window
{
protected string listContents;
public ListBox(int top1,int left1,string contents):base(top1,left1)
{
this.listContents = contents;
}

public override void DrawWindow()
{
Console.WriteLine(listContents);
}
}

public class Tester
{
static void Main()
{
Window[] win = new Window[2];
win[0] = new ListBox(1,2,"Fitst");
win[1] = new ListBox(3,4,"Second");
for(int i=0;i<2;i++)
{
win.DrawWindow();
}

Console.Read();
}
}
说是不能实例化,Window[] win = new Window[2];这个不算是实例吗?
------------------------------------------------------------------------------------------
三。对此释疑

幸好请教了一位耐心的老大。

Window[] win = new Window[2]
这句真正实例化的是数组对象,而是Window抽象类型。

你又在其后这样写:
win[0] = new ListBox(1,2,"Fitst");
win[1] = new ListBox(3,4,"Second");
其实还是把派生类的实例化放到数组元素里了。

如果你把上边new ListBox的两句注掉,改成一句win[0] = new Window(0,0)放进去,再试试
这时就编译不过了,并且会给你明确的提示。
------------------------------------------------------------------------------------------
四。系统总结一下MS关于抽象类的说法

任何情况下,抽象类都不应进行实例化,因此,正确定义其构造函数就非常重要。确保抽象类功能的正确性和扩展性也很重要。下列准则有助于确保抽象类能够正确地设计并在实现后可以按预期方式工作。

不要在抽象类型中定义公共的或受保护的内部(在 Visual Basic 中为 Protected Friend)构造函数。
具有 public 或 protected internal 可见性的构造函数用于能进行实例化的类型。任何情况下抽象类型都不能实例化。

应在抽象类中定义一个受保护构造函数或内部构造函数。
如果在抽象类中定义一个受保护构造函数,则在创建派生类的实例时,基类可执行初始化任务。内部构造函数可防止抽象类被用作其他程序集中的类型的基类。

对于您提供的每个抽象类,至少应提供一个具体的继承类型。
这样有助于库设计者在设计抽象类时找到问题所在。同时意味着开发人员在进行高级别开发时,即使不了解抽象类和继承,也可以使用具体类而不必学习这些概念。

抽象类具有以下特性:

抽象类不能实例化。
抽象类可以包含抽象方法和抽象访问器。
不能用 sealed(C# 参考)修饰符修改抽象类,这意味着抽象类不能被继承。
从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
在方法或属性声明中使用 abstract 修饰符以指示方法或属性不包含实现。

抽象方法具有以下特性:

抽象方法是隐式的虚方法。
只允许在抽象类中使用抽象方法声明。
因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。例如:
实现由一个重写方法提供,此重写方法是非抽象类的成员。
在抽象方法声明中使用 static 或 virtual 修饰符是错误的。
除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
在静态属性上使用 abstract 修饰符是错误的。
在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。
抽象类必须为所有接口成员提供实现。
实现接口的抽象类可以将接口方法映射到抽象方法上。


qltouming(缘木渔人)
2006-11-02