【问题标题】:Abstract Class in DelphiDelphi中的抽象类
【发布时间】:2011-09-05 10:23:20
【问题描述】:

我正在使用一个包含许多抽象类的组件套件。现在我想应用多态性,但是在创建对象时出现错误抽象类。

是否应该覆盖所有虚拟的方法,即使我不需要它?有什么变通方法或解决方案吗?

【问题讨论】:

  • 您在运行时或编译时得到“错误抽象类”吗?编译时应该给出 E2402: Constructing instance of abstract class '%s'

标签: delphi abstract delphi-2009


【解决方案1】:

为了创建一个类的实例,您需要覆盖所有声明为虚拟抽象的方法。即使你不使用它们。

如果你真的想要解决方法,你可以使用空方法。但我不建议这样做。

并添加有关该主题的更多信息:

如果用虚拟抽象声明方法是抽象的:

procedure MyMethod(const AMyParameter: Integer); virtual; abstract;

琐事:您甚至可以将方法重写为抽象:

procedure MyMethod(const AMyParameter: Integer); override; abstract;

您需要重写这些方法才能从该类实例化。

您可以将整个类声明为抽象类:

type
  TMyClass = class abstract (TMyAncestor)
  end;

如果您尝试实例化该类,则会收到警告。

对应的是一个密封类:

type
  TMyClass = class sealed (TMyAncestor)
  end;

如果您尝试从该类继承,则会收到警告。

您也可以密封方法,但您需要关键字 final。

procedure MyMethod(const AMyParameter: Integer); override; final;

【讨论】:

  • 我认为你不必实现所有抽象方法,因为你不调用它们。它只是给你一个编译器警告。如果在运行时调用,则会引发 EAbstractError
  • 我认为您需要检查此答案中所述的事实
  • 请注意,如果您尝试使用抽象类名直接实现它们,您只会收到警告,例如Obj := TAbstractObject.Create;。如果您使用返回类类型的“类”变量或方法,则可能会在没有编译时警告的情况下获得抽象错误。例如TAbstractClass = class of TAbstractObject; function GetClass: TAbstractClass; ... Obj := GetClass.Create; // <-- boom
  • “即使你不使用它们” - 嗯....我不知道这个。!因此,您有一个具有 T0.LockDoor() 抽象方法的父类 (T0)。你有 9 个子类实现了父类的抽象方法。但是第10类有点特殊,不需要实现。它有一个 StartEngine() 方法... [待续...]
  • [Continuation] .......所以,您将 T10.LockDoor 实现为一个空方法,然后在您的程序中调用它(偶然地),以为您的门已锁定。我个人会让这种方法在 T10 中未实现。如果它被意外调用,你会在测试过程中得到一个 EAbstract 错误,并且你会知道调用的是 T10.LockDoor 而不是 T10.StartEngine。
【解决方案2】:

Delphi 本身没有抽象类,只有抽象方法。调用抽象方法会引发抽象方法异常。

简单地说,你不能调用抽象方法。如果编译器检测到您使用抽象方法实例化一个类,它会发出警告。好的做法是要求编译器将这些警告转化为错误。

【讨论】:

  • Good practise is to ask the compiler to turn these warnings into errors. 我们如何做到这一点?
  • @David,不完全是,您可以使用 TMyClass = class abstract (TMyParent) 创建一个抽象类(即使没有抽象方法)...
  • @johan 项目选项,提示和警告,任何升温都可以转化为错误
  • @David,很酷不知道你可以升级你的警告。
  • “好的做法是要求编译器将这些警告转化为错误。”良好的做法 - 是的。 IMO 更好的做法是改用接口,这会强制您在使用时实现它们。
【解决方案3】:

你的后代类仍然是抽象的,如果

  1. 声明为abstract,或者
  2. 它至少有一个声明为抽象的方法,或者
  3. 它不会覆盖和实现其祖先的所有抽象方法

【讨论】:

  • 是的 - 我发现只抽象那些总是必须被覆盖的方法更容易。所有其他的东西都得到“空”的虚拟方法。也就是说,为什么 TThread.execute 不是抽象的?
  • @Martin James:你说得对,它实际上应该是抽象的,但想象一下,有人实例化了一个 TThread 后代并忘记覆盖 Execute:一个 EAbstractError 将在后台线程中引发并且不会被处理,所以没有人会意识到发生了什么。这种错误不容易发现。
  • @ondrej - 检查上面答案中的 cmets。将整个类标记为抽象类没有任何作用。
【解决方案4】:

如果你重写抽象构造函数会产生错误,因为它会自动将继承的新构造函数放入新构造函数中,如果你使用代码自动完成,它当然会调用抽象构造函数。

例如

type
  TMyclass = class (TObject)
  public
    constructor Create(AOwner : TComponent); dynamic; abstract;
  end;

  TMyclass2 = class(TMyclass)
  public
    Constructor Create(AOwner : TComponent); override;
  end;

implementation

constructor TMyclass2.Create(AOwner: TComponent);
begin
  inherited;

end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-25
    • 2012-09-16
    相关资源
    最近更新 更多