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

时间:2013-05-02 16:42:56

标签: 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指令标记。但是,该方法 CAN NOT 被标记为覆盖:基类中不存在具有该签名的方法,并且将override指令添加到该方法会导致编译器错误:

  

[DCC错误] .... E2037'aMethod'的声明与之前的声明不同。

这很明显,因为在TBaseClass中不存在具有该签名的方法。

只有'aMethod(const s:string)'存在于基类中,并且该方法被标记为'override' - ,因此基类中没有任何内容被隐藏。

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

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

1 个答案:

答案 0 :(得分:3)

我最近在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中得到修复。所以我最终在Indy做的事情是:

  1. 将基本TIdStack方法声明为overload; virtual; abstract;

  2. TIdStackBDSBase
  3. ,将覆盖方法声明为overload; override;,然后:

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

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

  4. 换句话说,以下代码适用于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;