delphi - 为什么在重载基类中引入的抽象方法时编译器会发出警告?

标签 delphi inheritance delphi-xe compiler-warnings

我有这样的代码:

TBaseClass = class(TObject)
protected
  procedure aMethod(const s:string);virtual;abstract;
end;

TDerivedClass = class(TBaseClass)
protected
   procedure aMethod(const s:string);overload;override;
   procedure aMethod(const s:string;const x:integer);overload;
end;

编译器生成警告:

[DCC 警告].... W1010 方法“aMethod”隐藏基类型“TBaseClass”的虚拟方法

单击警告会将我发送到“aMethod(const s:string;const x:integer);”因为它没有用 override 指令标记。但是,该方法不能被标记为 override:基类中不存在具有该签名的方法,并且向该方法添加 override 指令会导致编译器错误:

[DCC Error].... E2037 Declaration of 'aMethod' differs from previous declaration.

这是显而易见的,因为 TBaseClass 中不存在具有该签名的方法。

基类中仅存在“aMethod(const s:string)”,并且该方法被标记为“覆盖” - 因此基类中根本没有隐藏任何内容。

为什么这不是一个错误的警告?(这也不是我遇到的第一个警告......)

对另一个问题的引用是不正确的,IMO。 我有一个解决方案 - 我只是使用了重构,并重命名了有问题的方法。 但我并不是在寻找解决方案,这很简单。我正在寻找对此警告的解释。这个设计有问题吗? (也许一起使用重载和覆盖并不是一个好的设计 - 我可以同意这一点,但这不是编译器警告的真正含义。)

最佳答案

我最近在 Indy 中遇到了同样的问题。它的TIdStack基类有抽象 GetSocketOption()SetSocketOption()方法TIdStackBDSBase将使用其自己的抽象方法进行重写和重载,以便其后代( TIdStackWindows 等)进行重写。我遇到了这些完全相同的编译器错误。

例如:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle;
      ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
      out AOptVal: Integer); virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); overload; virtual; abstract;
    ...
  end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
var
  LBuf, LLen: Integer;
begin
  LLen := SizeOf(LBuf);
  GetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
  AOptVal := LBuf;
end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

procedure TIdStackWindows.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
begin
  ...
end;

无论是否TIdStack.GetSocketOption()声明为overload无论是否,XE2都会报告此错误:

[DCC Error] IdStackWindows.pas(296): E2137 Method 'GetSocketOption' not found in base class

事实证明,在某些情况下(例如 Indy 的情况),编译器要求将基类方法声明为 overload (即使基类本身没有相应的重载方法)以便派生类重写+重载它。

但是,当我这样做时,它在 XE2 及更早版本中不起作用,导致“隐藏虚拟方法”警告和其他错误。这似乎已在 XE3 中得到修复。所以我最终在印地要做的是:

  1. 声明基数 TIdStack方法如overload; virtual; abstract; .

  2. TIdStackBDSBase ,将重写方法声明为 overload; override; ,那么:

    a.在XE2及更早版本中,将重载方法声明为 reintroduce; overload; ,并声明单独的非重载virtual; abstract;后代的方法override .

    b.在XE3及更高版本中,将重载方法声明为 overload; virtual; abstract; ,并让后代override他们通常。

换句话说,下面的代码在XE3中可以运行,但在XE2中不行:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); overload; virtual; abstract;
    ...
  end;

  procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
  var
    LBuf, LLen: Integer;
  begin
    LLen := SizeOf(LBuf);
    GetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
    AOptVal := LBuf;
  end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

  procedure TIdStackWindows.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
  begin
    ...
  end;

下面的代码可以在 XE2 中运行:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); virtual; abstract;
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); reintroduce; overload;
    ...
  end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
var
  LBuf, LLen: Integer;
begin
  LLen := SizeOf(LBuf);
  WSGetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
  AOptVal := LBuf;
end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
begin
  WSGetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

  procedure TIdStackWindows.WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
  begin
    ...
  end;

关于delphi - 为什么在重载基类中引入的抽象方法时编译器会发出警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16343394/

相关文章:

delphi - Delphi 7 中的类变量

xml - 使用 MSXML 加载 XML 时如何获得英文错误消息

delphi - 寻找OSD组件

c++ - 在 C++ 继承中,当指向基类的指针对象指向派生类时,不调用派生类析构函数

windows - 将非 VCL 窗口添加到 VCL 对齐队列

delphi - 如何查看我们在亚历山大信任的项目?

c++ - 仅知道基本类型时添加到 Vector 的函数

css - 不明白语句 "individual inherited values are not possible with any shorthand property"

Delphi XE Data Snap TCP/IP 客户端登录表单

delphi - 仅在 Rad Studio XE 中查看当前文件的 Delphi 断点?