最近我在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
中,将被覆盖的方法声明为
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中可以工作:
```html
以下代码在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;
TBaseClass
中将aMethod
标记为overload;virtual;abstract;
,编译器警告就会消失(即使TBaseClass
没有定义任何重载变体)。 - J...