2013-05-02 36 views
3

我有这样的代码:为什么编译器在重载基类中引入的抽象方法时会发出警告?

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标记控制装置:该签名没有方法存在于基类,并添加覆盖指令,该方法会导致编译器错误:

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

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

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

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

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

+0

的可能重复的[Delphi的:方法“创建”隐藏基部的虚拟方法 - 但它在那里(http://stackoverflow.com/questions/9103263/delphi-method-create-hides-virtual-方法的基地,但它的权利在那里) – 2013-05-02 17:00:44

+0

@J ...:这不是一个骗局。他接受了解决方案。我有一个解决方案 - 这不是我要找的。我正在寻找一个解释。 – Vector 2013-05-02 17:19:49

+0

按照评论 - 我链接到最好的解决方案,可能是“为什么?”这个问题的最佳答案。在这里,但是(也在链接的标记dupe)http://stackoverflow.com/a/58167/327083 – 2013-05-02 17:26:56

回答

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中得到修复。所以,我最后不得不在印第安纳波利斯做的是:

  1. 申报基地TIdStack方法为overload; virtual; abstract;

  2. TIdStackBDSBase,声明重写的方法如overload; override;,则:

    一个。在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; 
+0

使用基类'过载;虚拟;抽象;'和派生类'过载; (对于声明的基本方法)和'重载;'(对于其余方法)我没有在XE2或D2010上得到'hidden virtual'编译器警告...... – 2013-05-02 17:48:16

+0

同样在这里 - 它增加了超载到基本声明和在XE-1中一切都很好。 – Vector 2013-05-02 17:55:45

+0

我已经更新了我的答案,其中包含导致XE2出错但在XE3中起作用的确切代码,以及我必须在XE2中使用哪些代码才能使其工作。 – 2013-05-02 18:17:20

相关问题