2013-05-02 46 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

相關問題